text: ;(function() {
  
  "use strict";
  
  BX.namespace("BX.Kanban");
  
  /**
   *
   * @param {object} options
   * @param {Element} options.renderTo
   * @param {BX.Kanban.Column[]} [options.columns]
   * @param {BX.Kanban.Item[]} [options.items]
   * @param {BX.Kanban.DropZone[]} [options.dropzones]
   * @param {object} [options.events]
   * @param {string} [options.itemType]
   * @param {string} [options.columnType]
   * @param {boolean} [options.canAddColumn]
   * @param {boolean} [options.canEditColumn]
   * @param {boolean} [options.canSortColumn]
   * @param {boolean} [options.canRemoveColumn]
   * @param {boolean} [options.canAddItem]
   * @param {boolean} [options.canSortItem]
   * @param {string} [options.dropZoneType]
   * @param {number} [options.dropZoneTimeout]
   * @param {string} [options.bgColor]
   * @param {object} [options.data] Custom Data For Grid
   * @param {object} [options.messages] Custom Messages For Grid
   * @constructor
   */
  BX.Kanban.Grid = function(options)
  {
  	if (!BX.type.isPlainObject(options))
  	{
  		throw new Error("BX.Kanban.Grid: 'options' is not an object.");
  	}
  
  	this.options = options;
  
  	if (!BX.type.isDomNode(options.renderTo))
  	{
  		throw new Error("BX.Kanban.Grid: 'renderTo' is not a DOMNode.");
  	}
  
  	this.renderTo = options.renderTo;
  	this.rendered = false;
  
  	this.layout = {
  		outerContainer: null,
  		innerContainer: null,
  		gridContainer: null,
  		earLeft: null,
  		earRight: null,
  		emptyStub: null,
  		loader: null
  	};
  
  	this.itemType = this.getItemType(options.itemType);
  	this.columnType = this.getColumnType(options.columnType);
  
  	this.messages = BX.type.isPlainObject(options.messages) ? options.messages : Object.create(null);
  
  	this.columns = Object.create(null);
  	this.columnsOrder = [];
  
  	/** @type {Object.<string, BX.Kanban.Item>} */
  	this.items = Object.create(null);
  
  	this.data = BX.type.isPlainObject(options.data) ? options.data : Object.create(null);
  	this.bgColor =
  		BX.Kanban.Utils.isValidColor(options.bgColor) || options.bgColor === "transparent" ? options.bgColor : "ffffff";
  
  	this.earTimer = null;
  	this.firstRenderComplete = null;
  	this.dragMode = BX.Kanban.DragMode.NONE;
  
  	/** @private **/
  	this.canAddColumn = false;
  	/** @private **/
  	this.canEditColumn = false;
  	/** @private **/
  	this.canSortColumn = false;
  	/** @private **/
  	this.canRemoveColumn = false;
  	/** @private **/
  	this.canAddItem = false;
  	/** @private **/
  	this.canSortItem = false;
  
  	this.dropZoneArea = new BX.Kanban.DropZoneArea(this, {
  		dropZoneType: options.dropZoneType,
  		dropZoneTimeout: options.dropZoneTimeout
  	});
  
  	this.data = Object.create(null);
  	this.setData(options.data);
  
  	this.loadData(options);
  
  	if (options.events)
  	{
  		for (var eventName in options.events)
  		{
  			if (options.events.hasOwnProperty(eventName))
  			{
  				BX.addCustomEvent(this, eventName, options.events[eventName]);
  			}
  		}
  	}
  
  	BX.addCustomEvent(this, "Kanban.Grid:onItemDragStart", BX.delegate(this.onItemDragStart, this));
  	BX.addCustomEvent(this, "Kanban.Grid:onItemDragStop", BX.delegate(this.onItemDragStop, this));
  
  	BX.addCustomEvent(this, "Kanban.Grid:onColumnDragStart", BX.delegate(this.onColumnDragStart, this));
  	BX.addCustomEvent(this, "Kanban.Grid:onColumnDragStop", BX.delegate(this.onColumnDragStop, this));
  };
  
  /**
   *
   * @enum {number}
   */
  BX.Kanban.DragMode = {
  	NONE: 0,
  	ITEM: 1,
  	COLUMN: 2
  };
  
  BX.Kanban.Grid.prototype =
  {
  	/**
  	 *
  	 * @param {object} options
  	 * @returns {BX.Kanban.Column|null}
  	 */
  	addColumn: function(options)
  	{
  		options = options || {};
  
  		if (this.getColumn(options.id) !== null)
  		{
  			return null;
  		}
  
  		var columnType = this.getColumnType(options.type);
  		var column = new columnType(options);
  		if (!(column instanceof BX.Kanban.Column))
  		{
  			throw new Error("Column type must be an instance of BX.Kanban.Column");
  		}
  
  		column.setGrid(this);
  		this.columns[column.getId()] = column;
  
  		var targetColumn = this.getColumn(options.targetId);
  		var targetIndex = BX.util.array_search(targetColumn, this.columnsOrder);
  		if (targetIndex >= 0)
  		{
  			this.columnsOrder.splice(targetIndex, 0, column);
  		}
  		else
  		{
  			this.columnsOrder.push(column);
  		}
  
  		if (this.isRendered())
  		{
  			if (targetColumn)
  			{
  				this.getGridContainer().insertBefore(column.render(), targetColumn.getContainer());
  			}
  			else
  			{
  				this.getGridContainer().appendChild(column.render());
  			}
  		}
  
  		return column;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Column|string|number} column
  	 * @returns {boolean}
  	 */
  	removeColumn: function(column)
  	{
  		column = this.getColumn(column);
  		if (!column)
  		{
  			return false;
  		}
  
  		this.removeColumnItems(column);
  
  		this.columnsOrder = this.columnsOrder.filter(function(element) {
  			return column !== element;
  		});
  
  		delete this.columns[column.getId()];
  
  		BX.remove(column.getContainer());
  
  		return true;
  	},
  
  	updateColumn: function(column, options)
  	{
  		column = this.getColumn(column);
  		if (!column)
  		{
  			return false;
  		}
  
  		column.setOptions(options);
  		column.render();
  
  		return true;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Column} currentColumn
  	 * @returns {BX.Kanban.Column}
  	 */
  	getNextColumnSibling: function(currentColumn)
  	{
  		var columnIndex = this.getColumnIndex(currentColumn);
  		var columns = this.getColumns();
  
  		return columnIndex !== -1 && columns[columnIndex + 1] ? columns[columnIndex + 1] : null;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Column} currentColumn
  	 * @returns {BX.Kanban.Column}
  	 */
  	getPreviousColumnSibling: function(currentColumn)
  	{
  		var columnIndex = this.getColumnIndex(currentColumn);
  		var columns = this.getColumns();
  
  		return columnIndex > 0 && columns[columnIndex - 1] ? columns[columnIndex - 1] : null;
  	},
  
  	/**
  	 *
  	 * @param {object} options
  	 * @param {string|number} options.id
  	 * @param {string|number} options.columnId
  	 * @param {string} [options.type]
  	 * @param {string|number} [options.targetId]
  	 * @returns {BX.Kanban.Item|null}
  	 */
  	addItem: function(options)
  	{
  		options = options || {};
  		var column = this.getColumn(options.columnId);
  		if (!column)
  		{
  			return null;
  		}
  
  		var itemType = this.getItemType(options.type);
  		var item = new itemType(options);
  		if (!(item instanceof BX.Kanban.Item))
  		{
  			throw new Error("Item type must be an instance of BX.Kanban.Item");
  		}
  
  		if (this.items[item.getId()])
  		{
  			return null;
  		}
  
  		item.setGrid(this);
  		this.items[item.getId()] = item;
  
  		var targetItem = this.getItem(options.targetId);
  		column.addItem(item, targetItem);
  
  		return item;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Item|string|number} itemId
  	 * @returns {BX.Kanban.Item}
  	 */
  	removeItem: function(itemId)
  	{
  		var item = this.getItem(itemId);
  		if (item)
  		{
  			var column = item.getColumn();
  			delete this.items[item.getId()];
  			column.removeItem(item);
  			item.dispose();
  		}
  
  		return item;
  	},
  
  	removeColumnItems: function(column)
  	{
  		column = this.getColumn(column);
  
  		var items = column.getItems();
  		column.removeItems();
  
  		items.forEach(function(item) {
  			this.removeItem(item);
  		}, this);
  	},
  
  	removeItems: function()
  	{
  		this.getColumns().forEach(function(column) {
  			this.removeColumnItems(column);
  		}, this);
  	},
  
  	updateItem: function(item, options)
  	{
  		item = this.getItem(item);
  		if (!item)
  		{
  			return false;
  		}
  
  		if (BX.Kanban.Utils.isValidId(options.columnId) && options.columnId !== item.getColumn().getId())
  		{
  			this.moveItem(item, this.getColumn(options.columnId), this.getItem(options.targetId));
  		}
  
  		var eventArgs = ['UPDATE', { task: item, options: options }];
  
  		BX.onCustomEvent(window, 'tasksTaskEvent', eventArgs);
  
  		item.setOptions(options);
  		item.render();
  
  		return true;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Item|string|number} item
  	 * @returns {boolean}
  	 */
  	hideItem: function(item)
  	{
  		item = this.getItem(item);
  		if (!item || !item.isVisible())
  		{
  			return false;
  		}
  
  		item.setOptions({ visible: false });
  
  		if (item.isCountable())
  		{
  			item.getColumn().decrementTotal();
  		}
  
  		item.getColumn().render();
  
  		return true;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Item|string|number} item
  	 * @returns {boolean}
  	 */
  	unhideItem: function(item)
  	{
  		item = this.getItem(item);
  		if (!item || item.isVisible())
  		{
  			return false;
  		}
  
  		item.setOptions({ visible: true });
  
  		if (item.isCountable())
  		{
  			item.getColumn().incrementTotal();
  		}
  
  		item.getColumn().render();
  
  		return true;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Column|string|number} column
  	 * @returns {BX.Kanban.Column}
  	 */
  	getColumn: function(column)
  	{
  		var columnId = column instanceof BX.Kanban.Column ? column.getId() : column;
  
  		return this.columns[columnId] ? this.columns[columnId] : null;
  	},
  
  	/**
  	 *
  	 * @returns {BX.Kanban.Column[]}
  	 */
  	getColumns: function()
  	{
  		return this.columnsOrder;
  	},
  
  	/**
  	 * @returns {number}
  	 */
  	getColumnsCount: function()
  	{
  		return this.columnsOrder.length;
  	},
  
  	/**
  	 *
  	 * @param column
  	 * @returns {number}
  	 */
  	getColumnIndex: function(column)
  	{
  		column = this.getColumn(column);
  
  		return BX.util.array_search(column, this.getColumns());
  	},
  
  	/**
  	 *
  	 * @param {string|number} item
  	 * @returns {BX.Kanban.Item}
  	 */
  	getItem: function(item)
  	{
  		var itemId = item instanceof BX.Kanban.Item ? item.getId() : item;
  
  		return this.items[itemId] ? this.items[itemId] : null;
  	},
  
  	/**
  	 *
  	 * @param {Element} itemNode
  	 * @returns {BX.Kanban.Item|null}
  	 */
  	getItemByElement: function(itemNode)
  	{
  		if (BX.type.isDomNode(itemNode) && itemNode.dataset.id && itemNode.dataset.type === "item")
  		{
  			return this.getItem(itemNode.dataset.id);
  		}
  
  		return null;
  	},
  
  	/**
  	 *
  	 * @returns {Object.<string, BX.Kanban.Item>}
  	 */
  	getItems: function()
  	{
  		return this.items;
  	},
  
  	/**
  	 *
  	 * @param {string} [className]
  	 * @returns {BX.Kanban.Item}
  	 */
  	getItemType: function(className)
  	{
  		var classFn = BX.Kanban.Utils.getClass(className);
  		if (BX.type.isFunction(classFn))
  		{
  			return classFn;
  		}
  
  		return this.itemType || BX.Kanban.Item;
  	},
  
  	/**
  	 *
  	 * @param {string} [className]
  	 * @returns {BX.Kanban.Column}
  	 */
  	getColumnType: function(className)
  	{
  		var classFn = BX.Kanban.Utils.getClass(className);
  		if (BX.type.isFunction(classFn))
  		{
  			return classFn;
  		}
  
  		return this.columnType || BX.Kanban.Column;
  	},
  
  	/**
  	 *
  	 * @returns {BX.Kanban.DropZoneArea}
  	 */
  	getDropZoneArea: function()
  	{
  		return this.dropZoneArea;
  	},
  
  	/**
  	 *
  	 * @returns {object}
  	 */
  	getData: function()
  	{
  		return this.data;
  	},
  
  	setData: function(data)
  	{
  		if (BX.type.isPlainObject(data))
  		{
  			this.data = data;
  		}
  	},
  
  	getBgColor: function()
  	{
  		return this.bgColor;
  	},
  
  	getBgColorStyle: function()
  	{
  		return this.getBgColor() === "transparent" ? this.getBgColor() : "#" + this.getBgColor();
  	},
  
  	/**
  	 *
  	 * @returns {object}
  	 */
  	getOptions: function()
  	{
  		return this.options;
  	},
  
  	/**
  	 *
  	 * @param {object} json
  	 * @param {BX.Kanban.Column[]} [json.columns]
  	 * @param {BX.Kanban.Item[]} [json.items]
  	 * @param {BX.Kanban.DropZone[]} [json.dropZones]
  	 */
  	loadData: function(json)
  	{
  		var needToDraw = this.isRendered();
  		this.setRenderStatus(false);
  
  		var boolOptions = [
  			"canAddColumn", "canEditColumn", "canSortColumn", "canRemoveColumn", "canAddItem", "canSortItem"
  		];
  
  		boolOptions.forEach(function(boolOption) {
  			if (BX.type.isBoolean(json[boolOption]))
  			{
  				this[boolOption] = json[boolOption];
  			}
  		}, this);
  
  		if (BX.type.isArray(json.columns))
  		{
  			json.columns.forEach(function(column) {
  
  				if (column && BX.Kanban.Utils.isValidId(column.id) && this.getColumn(column.id))
  				{
  					this.updateColumn(column.id, column);
  				}
  				else
  				{
  					this.addColumn(column);
  				}
  
  			}, this);
  		}
  
  		if (BX.type.isArray(json.items))
  		{
  			json.items.forEach(function(item) {
  
  				if (item && BX.Kanban.Utils.isValidId(item.id) && this.getItem(item.id))
  				{
  					this.updateItem(item.id, item);
  				}
  				else
  				{
  					this.addItem(item);
  				}
  
  			}, this);
  		}
  
  		if (BX.type.isArray(json.dropZones))
  		{
  			json.dropZones.forEach(function(dropzone) {
  
  				if (dropzone && BX.Kanban.Utils.isValidId(dropzone.id) && this.getDropZoneArea().getDropZone(dropzone.id))
  				{
  					this.getDropZoneArea().updateDropZone(dropzone.id, dropzone);
  				}
  				else
  				{
  					this.getDropZoneArea().addDropZone(dropzone);
  				}
  
  			}, this);
  		}
  
  		if (needToDraw)
  		{
  			this.draw();
  		}
  	},
  
  	/**
  	 * Draws Kanban on the page
  	 *
  	 */
  	draw: function()
  	{
  		var docFragment = document.createDocumentFragment();
  		var columns = this.getColumns();
  		for (var i = 0; i < columns.length; i++)
  		{
  			var column = columns[i];
  			docFragment.appendChild(column.render());
  		}
  
  		BX.cleanNode(this.getGridContainer());
  		this.getGridContainer().appendChild(docFragment);
  
  		this.getDropZoneArea().render();
  
  		if (!this.isRendered())
  		{
  			this.renderLayout();
  			this.adjustLayout();
  			this.setRenderStatus(true);
  			BX.onCustomEvent(this, "Kanban.Grid:onFirstRender", [this]);
  		}
  		else
  		{
  			this.adjustLayout();
  		}
  
  		this.adjustEmptyStub();
  
  		BX.onCustomEvent(this, "Kanban.Grid:onRender", [this]);
  
  		this.firstRenderComplete = true;
  	},
  
  	renderLayout: function()
  	{
  		if (this.getOuterContainer().parentNode)
  		{
  			return;
  		}
  
  		var innerContainer = this.getInnerContainer();
  		innerContainer.appendChild(this.getEmptyStub());
  		innerContainer.appendChild(this.getLeftEar());
  		innerContainer.appendChild(this.getRightEar());
  		innerContainer.appendChild(this.getDropZoneArea().getContainer());
  		innerContainer.appendChild(this.getLoader());
  		innerContainer.appendChild(this.getGridContainer());
  
  		var outerContainer = this.getOuterContainer();
  		outerContainer.appendChild(innerContainer);
  
  		this.renderTo.appendChild(this.getOuterContainer());
  
  
  		BX.bind(window, "resize", this.adjustLayout.bind(this));
  		BX.bind(window, "scroll", this.adjustHeight.bind(this));
  	},
  
  	isRendered: function()
  	{
  		return this.rendered;
  	},
  
  	setRenderStatus: function(status)
  	{
  		if (BX.type.isBoolean(status))
  		{
  			this.rendered = status;
  		}
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getLeftEar: function()
  	{
  		if (this.layout.earLeft)
  		{
  			return this.layout.earLeft;
  		}
  
  		this.layout.earLeft = BX.create("div", {
  			attrs: {
  				className: "main-kanban-ear-left"
  			},
  			events: {
  				mouseenter: this.scrollToLeft.bind(this),
  				mouseleave: this.stopAutoScroll.bind(this)
  			}
  		});
  
  		return this.layout.earLeft;
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getRightEar: function()
  	{
  		if (this.layout.earRight)
  		{
  			return this.layout.earRight;
  		}
  
  		this.layout.earRight = BX.create("div", {
  			attrs: {
  				className: "main-kanban-ear-right"
  			},
  			events: {
  				mouseenter: this.scrollToRight.bind(this),
  				mouseleave: this.stopAutoScroll.bind(this)
  			}
  		});
  
  		return this.layout.earRight;
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getRenderToContainer: function()
  	{
  		return this.renderTo;
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getOuterContainer: function()
  	{
  		if (this.layout.outerContainer)
  		{
  			return this.layout.outerContainer;
  		}
  
  		this.layout.outerContainer = BX.create("div", {
  			props: {
  				className: "main-kanban"
  			},
  			style: {
  				backgroundColor: this.getBgColorStyle()
  			}
  		});
  
  		return this.layout.outerContainer;
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getInnerContainer: function()
  	{
  		if (this.layout.innerContainer)
  		{
  			return this.layout.innerContainer;
  		}
  
  		this.layout.innerContainer = BX.create("div", {
  			props: {
  				className: "main-kanban-inner"
  			},
  			style: {
  				backgroundColor: this.getBgColorStyle()
  			}
  		});
  
  		return this.layout.innerContainer;
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getGridContainer: function()
  	{
  		if (this.layout.gridContainer)
  		{
  			return this.layout.gridContainer;
  		}
  
  		this.layout.gridContainer = BX.create("div", {
  			props: {
  				className: "main-kanban-grid"
  			},
  			events: {
  				scroll: this.adjustEars.bind(this)
  			}
  		});
  		return this.layout.gridContainer;
  	},
  
  	/**
  	 *
  	 * @returns {Element}
  	 */
  	getEmptyStub: function()
  	{
  		if (this.layout.emptyStub)
  		{
  			return this.layout.emptyStub;
  		}
  
  		this.layout.emptyStub = BX.create("div", {
  			attrs: {
  				className: "main-kanban-no-data"
  			},
  			children: [
  				BX.create("div", {
  					attrs: {
  						className: "main-kanban-no-data-inner"
  					},
  					children: [
  						BX.create("div", {
  							attrs: {
  								className: "main-kanban-no-data-image"
  							}
  						}),
  						BX.create("div", {
  							attrs: {
  								className: "main-kanban-no-data-text"
  							},
  							text: this.getMessage("NO_DATA")
  						})
  					]
  				})
  			]
  		});
  
  		return this.layout.emptyStub;
  	},
  
  	getLoader: function()
  	{
  		if (this.layout.loader)
  		{
  			return this.layout.loader;
  		}
  
  		this.layout.loader = BX.create("div", {
  			props: {
  				className: "main-kanban-loader-container"
  			},
  			html:
  			'<svg class="main-kanban-loader-circular" viewBox="25 25 50 50">' +
  				'<circle class="main-kanban-loader-path" cx="50" cy="50" r="20" fill="none" stroke-miterlimit="10"/>' +
  			'</svg>'
  		});
  
  		return this.layout.loader;
  	},
  
  	adjustLayout: function()
  	{
  		this.adjustWidth();
  		this.adjustHeight();
  		this.adjustEars();
  	},
  
  	adjustEars: function()
  	{
  		var grid = this.getGridContainer();
  		var scroll = grid.scrollLeft;
  
  		var isLeftVisible = scroll > 0;
  		var isRightVisible = grid.scrollWidth > (Math.round(scroll + grid.offsetWidth));
  
  		this.getOuterContainer().classList[isLeftVisible ? "add" : "remove"]("main-kanban-left-ear-shown");
  		this.getOuterContainer().classList[isRightVisible ? "add" : "remove"]("main-kanban-right-ear-shown");
  	},
  
  	adjustWidth: function()
  	{
  		this.getOuterContainer().style.width = this.renderTo.offsetWidth + "px";
  	},
  
  	adjustHeight: function()
  	{
  		var outerContainer = this.getOuterContainer();
  		var innerContainer = this.getInnerContainer();
  
  		if (outerContainer.getBoundingClientRect().top >= 15) //@see .main-kanban-fixed:top
  		{
  			var height = document.documentElement.clientHeight - innerContainer.getBoundingClientRect().top;
  			innerContainer.style.height = height + "px";
  
  			if (innerContainer.classList.contains("main-kanban-fixed"))
  			{
  				BX.onCustomEvent(this, "Kanban.Grid:onFixedModeEnd", [this]);
  			}
  
  			outerContainer.style.minHeight = document.documentElement.clientHeight + "px";
  			innerContainer.style.removeProperty("top");
  			innerContainer.style.removeProperty("left");
  			innerContainer.style.removeProperty("width");
  			innerContainer.classList.remove("main-kanban-fixed");
  		}
  		else
  		{
  			if (!innerContainer.classList.contains("main-kanban-fixed"))
  			{
  				BX.onCustomEvent(this, "Kanban.Grid:onFixedModeStart", [this]);
  			}
  
  			var rectArea = this.renderTo.getBoundingClientRect();
  			innerContainer.style.left = rectArea.left + "px";
  			innerContainer.style.width = rectArea.width + "px";
  			innerContainer.style.removeProperty("height");
  			innerContainer.classList.add("main-kanban-fixed");
  		}
  	},
  
  	adjustEmptyStub: function()
  	{
  		var isVisible = true;
  
  		var items = this.getItems();
  		for (var itemId in items)
  		{
  			var item = items[itemId];
  			if (item.isVisible())
  			{
  				isVisible = false;
  				break;
  			}
  		}
  
  		this.getInnerContainer().classList[isVisible ? "add" : "remove"]("main-kanban-no-data-mode");
  	},
  
  	moveItem: function(item, targetColumn, beforeItem)
  	{
  		item = this.getItem(item);
  		targetColumn = this.getColumn(targetColumn);
  		beforeItem = this.getItem(beforeItem);
  
  		if (!item || !targetColumn || item === beforeItem)
  		{
  			return false;
  		}
  
  		var currentColumn = item.getColumn();
  		currentColumn.removeItem(item);
  		targetColumn.addItem(item, beforeItem);
  
  		return true;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Column|string|number} column
  	 * @param {BX.Kanban.Column|string|number} [targetColumn]
  	 * @returns {boolean}
  	 */
  	moveColumn: function(column, targetColumn)
  	{
  		column = this.getColumn(column);
  		targetColumn = this.getColumn(targetColumn);
  		if (!column || column === targetColumn)
  		{
  			return false;
  		}
  
  		var columnIndex = BX.util.array_search(column, this.columnsOrder);
  		this.columnsOrder.splice(columnIndex, 1);
  
  		var targetIndex = BX.util.array_search(targetColumn, this.columnsOrder);
  		if (targetIndex >= 0)
  		{
  			this.columnsOrder.splice(targetIndex, 0, column);
  			if (this.isRendered())
  			{
  				column.getContainer().parentNode.insertBefore(column.getContainer(), targetColumn.getContainer());
  			}
  		}
  		else
  		{
  			this.columnsOrder.push(column);
  			if (this.isRendered())
  			{
  				column.getContainer().parentNode.appendChild(column.getContainer());
  			}
  		}
  
  		return true;
  	},
  
  	/**
  	 *
  	 * @returns {boolean}
  	 */
  	canAddColumns: function()
  	{
  		return this.canAddColumn;
  	},
  
  	/**
  	 *
  	 * @returns {boolean}
  	 */
  	canEditColumns: function()
  	{
  		return this.canEditColumn;
  	},
  
  	/**
  	 *
  	 * @returns {boolean}
  	 */
  	canSortColumns: function()
  	{
  		return this.canSortColumn;
  	},
  
  	/**
  	 *
  	 * @returns {boolean}
  	 */
  	canRemoveColumns: function()
  	{
  		return this.canRemoveColumn;
  	},
  
  	/**
  	 *
  	 * @returns {boolean}
  	 */
  	canAddItems: function()
  	{
  		return this.canAddItem;
  	},
  
  	/**
  	 *
  	 * @returns {boolean}
  	 */
  	canSortItems: function()
  	{
  		return this.canSortItem;
  	},
  
  	scrollToRight: function()
  	{
  		this.earTimer = setInterval(function() {
  			this.getGridContainer().scrollLeft += 10;
  		}.bind(this), 20)
  	},
  
  	scrollToLeft: function()
  	{
  		this.earTimer = setInterval(function() {
  			this.getGridContainer().scrollLeft -= 10;
  		}.bind(this), 20)
  	},
  
  	stopAutoScroll: function()
  	{
  		clearInterval(this.earTimer);
  
  		//?
  		jsDD.refreshDestArea();
  	},
  
  	/**
  	 *
  	 * @returns {BX.Kanban.DragMode}
  	 */
  	getDragMode: function()
  	{
  		return this.dragMode;
  	},
  
  	getDragModeCode: function(mode)
  	{
  		for (var code in BX.Kanban.DragMode)
  		{
  			if (BX.Kanban.DragMode[code] === mode)
  			{
  				return code;
  			}
  		}
  
  		return null;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.DragMode} mode
  	 */
  	setDragMode: function(mode)
  	{
  		var code = this.getDragModeCode(mode);
  		if (code !== null)
  		{
  			this.getOuterContainer().classList.add("main-kanban-drag-mode-" + code.toLowerCase());
  			this.dragMode = mode;
  		}
  	},
  
  	resetDragMode: function()
  	{
  		var code = this.getDragModeCode(this.getDragMode());
  		if (code !== null)
  		{
  			this.getOuterContainer().classList.remove("main-kanban-drag-mode-" + code.toLowerCase());
  		}
  
  		this.dragMode = BX.Kanban.DragMode.NONE;
  	},
  
  	onItemDragStart: function(item)
  	{
  		this.setDragMode(BX.Kanban.DragMode.ITEM);
  
  		var items = this.getItems();
  		for (var itemId in items)
  		{
  			items[itemId].enableDropping();
  		}
  
  		this.getColumns().forEach(function(/*BX.Kanban.Column*/column) {
  			column.enableDropping();
  		});
  
  		this.getDropZoneArea().emptyAll();
  		this.getDropZoneArea().show();
  	},
  
  	onItemDragStop: function(item)
  	{
  		this.resetDragMode();
  		this.getDropZoneArea().hide();
  
  		//@see onItemDragEnd
  		// var items = this.getItems();
  		// for (var itemId in items)
  		// {
  		// 	items[itemId].disableDropping();
  		// }
  		//
  		// this.getColumns().forEach(function(/*BX.Kanban.Column*/column) {
  		// 	column.disableDropping();
  		// });
  	},
  
  	onColumnDragStart: function(column)
  	{
  		this.setDragMode(BX.Kanban.DragMode.COLUMN);
  	},
  
  	onColumnDragStop: function(column)
  	{
  		this.resetDragMode();
  	},
  
  	/**
  	 *
  	 * @param {string} eventName
  	 * @param {array} eventArgs
  	 * @param {function} onFulfilled
  	 * @param {function} onRejected
  	 */
  	getEventPromise: function(eventName, eventArgs, onFulfilled, onRejected)
  	{
  		var promises = [];
  
  		eventArgs = BX.type.isArray(eventArgs) ? eventArgs : [];
  		BX.onCustomEvent(this, eventName, [promises].concat(eventArgs));
  
  		var promise = new BX.Promise();
  		var firstPromise = promise;
  
  		for (var i = 0; i < promises.length; i++)
  		{
  			promise = promise.then(promises[i]);
  		}
  
  		promise.then(
  			BX.type.isFunction(onFulfilled) ? onFulfilled : null,
  			BX.type.isFunction(onRejected) ? onRejected : null
  		);
  
  		return firstPromise;
  	},
  
  	fadeOut: function()
  	{
  		this.getOuterContainer().classList.add("main-kanban-faded");
  	},
  
  	fadeIn: function()
  	{
  		this.getOuterContainer().classList.remove("main-kanban-faded");
  	},
  
  	getMessage: function(messageId)
  	{
  		return messageId in this.messages ? this.messages[messageId] : BX.message("MAIN_KANBAN_" + messageId);
  	}
  };
  
  BX.Kanban.DragEvent = function(options)
  {
  	this.item = null;
  	this.targetColumn = null;
  	this.targetItem = null;
  	this.action = true;
  };
  
  BX.Kanban.DragEvent.prototype =
  {
  	allowAction: function()
  	{
  		this.action = true;
  	},
  
  	denyAction: function()
  	{
  		this.action = false;
  	},
  
  	isActionAllowed: function()
  	{
  		return this.action;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Item} item
  	 */
  	setItem: function(item)
  	{
  		this.item = item;
  	},
  
  	/**
  	 *
  	 * @returns {BX.Kanban.Item}
  	 */
  	getItem: function()
  	{
  		return this.item;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Item} item
  	 */
  	setTargetItem: function(item)
  	{
  		this.targetItem = item;
  	},
  
  	/**
  	 *
  	 * @returns {BX.Kanban.Item}
  	 */
  	getTargetItem: function()
  	{
  		return this.targetItem;
  	},
  
  	/**
  	 *
  	 * @param {BX.Kanban.Column} targetColumn
  	 */
  	setTargetColumn: function(targetColumn)
  	{
  		this.targetColumn = targetColumn;
  	},
  
  	/**
  	 *
  	 * @returns {BX.Kanban.Column}
  	 */
  	getTargetColumn: function()
  	{
  		return this.targetColumn;
  	}
  };
  
  })();