/** gridstack.js 0.6.4 - IE and older browsers Polyfills for this library @preserve*/
/**
 * https://gridstackjs.com/
 * (c) 2019-2020 Alain Dumesny
 * gridstack.js may be freely distributed under the MIT license.
*/

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
Number.isNaN = Number.isNaN || function isNaN(input) {
  return typeof input === 'number' && input !== input;
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
if (!Array.prototype.find) {
  Object.defineProperty(Array.prototype, 'find', {
    value: function (predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return kValue.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return undefined.
      return undefined;
    },
    configurable: true,
    writable: true
  });
}

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex
if (!Array.prototype.findIndex) {
  Object.defineProperty(Array.prototype, 'findIndex', {
    value: function(predicate) {
      // 1. Let O be ? ToObject(this value).
      if (this == null) {
        throw new TypeError('"this" is null or not defined');
      }

      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0;

      // 3. If IsCallable(predicate) is false, throw a TypeError exception.
      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
      var thisArg = arguments[1];

      // 5. Let k be 0.
      var k = 0;

      // 6. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kValue be ? Get(O, Pk).
        // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
        // d. If testResult is true, return k.
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return k;
        }
        // e. Increase k by 1.
        k++;
      }

      // 7. Return -1.
      return -1;
    },
    configurable: true,
    writable: true
  });
}
/**
 * gridstack.js 0.6.4
 * https://gridstackjs.com/
 * (c) 2014-2020 Alain Dumesny, Dylan Weiss, Pavel Reznikov
 * gridstack.js may be freely distributed under the MIT license.
 * @preserve
*/
(function(factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery', 'exports'], factory);
  } else if (typeof exports !== 'undefined') {
    var jQueryModule;

    try { jQueryModule = require('jquery'); } catch (e) {}

    factory(jQueryModule || window.jQuery, exports);
  } else {
    factory(window.jQuery, window);
  }
})(function($, scope) {

  // checks for obsolete method names
  var obsolete = function(f, oldName, newName, rev) {
    var wrapper = function() {
      console.warn('gridstack.js: Function `' + oldName + '` is deprecated in ' + rev + ' and has been replaced ' +
      'with `' + newName + '`. It will be **completely** removed in v1.0');
      return f.apply(this, arguments);
    };
    wrapper.prototype = f.prototype;

    return wrapper;
  };

  // checks for obsolete grid options (can be used for any fields, but msg is about options)
  var obsoleteOpts = function(opts, oldName, newName, rev) {
    if (opts[oldName] !== undefined) {
      opts[newName] = opts[oldName];
      console.warn('gridstack.js: Option `' + oldName + '` is deprecated in ' + rev + ' and has been replaced with `' +
        newName + '`. It will be **completely** removed in v1.0');
    }
  };

  // checks for obsolete grid options which are gone
  var obsoleteOptsDel = function(opts, oldName, rev, info) {
    if (opts[oldName] !== undefined) {
      console.warn('gridstack.js: Option `' + oldName + '` is deprecated in ' + rev + info);
    }
  };

  // checks for obsolete Jquery element attributes
  var obsoleteAttr = function(el, oldName, newName, rev) {
    var oldAttr = el.attr(oldName);
    if (oldAttr !== undefined) {
      el.attr(newName, oldAttr);
      console.warn('gridstack.js: attribute `' + oldName + '`=' + oldAttr + ' is deprecated on this object in ' + rev + ' and has been replaced with `' +
        newName + '`. It will be **completely** removed in v1.0');
    }
  };

  var Utils = {

    isIntercepted: function(a, b) {
      return !(a.x + a.width <= b.x || b.x + b.width <= a.x || a.y + a.height <= b.y || b.y + b.height <= a.y);
    },

    sort: function(nodes, dir, column) {
      if (!column) {
        var widths = nodes.map(function(node) { return node.x + node.width; });
        column = Math.max.apply(Math, widths);
      }

      if (dir === -1)
        return Utils.sortBy(nodes, function(n) { return -(n.x + n.y * column); });
      else
        return Utils.sortBy(nodes, function(n) { return (n.x + n.y * column); });
    },

    createStylesheet: function(id, parent) {
      var style = document.createElement('style');
      style.setAttribute('type', 'text/css');
      style.setAttribute('data-gs-style-id', id);
      if (style.styleSheet) {
        style.styleSheet.cssText = '';
      } else {
        style.appendChild(document.createTextNode(''));
      }
      if (!parent) { parent = document.getElementsByTagName('head')[0]; } // default to head
      parent.insertBefore(style, parent.firstChild);
      return style.sheet;
    },

    removeStylesheet: function(id) {
      $('STYLE[data-gs-style-id=' + id + ']').remove();
    },

    insertCSSRule: function(sheet, selector, rules, index) {
      if (typeof sheet.insertRule === 'function') {
        sheet.insertRule(selector + '{' + rules + '}', index);
      } else if (typeof sheet.addRule === 'function') {
        sheet.addRule(selector, rules, index);
      }
    },

    toBool: function(v) {
      if (typeof v === 'boolean') {
        return v;
      }
      if (typeof v === 'string') {
        v = v.toLowerCase();
        return !(v === '' || v === 'no' || v === 'false' || v === '0');
      }
      return Boolean(v);
    },

    _collisionNodeCheck: function(n) {
      return n !== this.node && Utils.isIntercepted(n, this.nn);
    },

    _didCollide: function(bn) {
      return Utils.isIntercepted({x: this.n.x, y: this.newY, width: this.n.width, height: this.n.height}, bn);
    },

    _isAddNodeIntercepted: function(n) {
      return Utils.isIntercepted({x: this.x, y: this.y, width: this.node.width, height: this.node.height}, n);
    },

    parseHeight: function(val) {
      var height = val;
      var heightUnit = 'px';
      if (height && typeof height === 'string') {
        var match = height.match(/^(-[0-9]+\.[0-9]+|[0-9]*\.[0-9]+|-[0-9]+|[0-9]+)(px|em|rem|vh|vw|%)?$/);
        if (!match) {
          throw new Error('Invalid height');
        }
        heightUnit = match[2] || 'px';
        height = parseFloat(match[1]);
      }
      return {height: height, unit: heightUnit};
    },

    without:  function(array, item) {
      var index = array.indexOf(item);

      if (index !== -1) {
        array = array.slice(0);
        array.splice(index, 1);
      }

      return array;
    },

    sortBy: function(array, getter) {
      return array.slice(0).sort(function(left, right) {
        var valueLeft = getter(left);
        var valueRight = getter(right);

        if (valueRight === valueLeft) {
          return 0;
        }

        return valueLeft > valueRight ? 1 : -1;
      });
    },

    defaults: function(target) {
      var sources = Array.prototype.slice.call(arguments, 1);

      sources.forEach(function(source) {
        for (var prop in source) {
          if (source.hasOwnProperty(prop) && (!target.hasOwnProperty(prop) || target[prop] === undefined)) {
            target[prop] = source[prop];
          }
        }
      });

      return target;
    },

    clone: function(target) {
      return $.extend({}, target);
    },

    throttle: function(callback, delay) {
      var isWaiting = false;

      return function() {
        if (!isWaiting) {
          callback.apply(this, arguments);
          isWaiting = true;
          setTimeout(function() { isWaiting = false; }, delay);
        }
      };
    },

    removePositioningStyles: function(el) {
      var style = el[0].style;
      if (style.position) {
        style.removeProperty('position');
      }
      if (style.left) {
        style.removeProperty('left');
      }
      if (style.top) {
        style.removeProperty('top');
      }
      if (style.width) {
        style.removeProperty('width');
      }
      if (style.height) {
        style.removeProperty('height');
      }
    },
    getScrollParent: function(el) {
      var returnEl;
      if (el === null) {
        returnEl = null;
      } else if (el.scrollHeight > el.clientHeight) {
        returnEl = el;
      } else {
        returnEl = Utils.getScrollParent(el.parentNode);
      }
      return returnEl;
    },
    updateScrollPosition: function(el, ui, distance) {
      // is widget in view?
      var rect = el.getBoundingClientRect();
      var innerHeightOrClientHeight = (window.innerHeight || document.documentElement.clientHeight);
      if (rect.top < 0 ||
        rect.bottom > innerHeightOrClientHeight
      ) {
        // set scrollTop of first parent that scrolls
        // if parent is larger than el, set as low as possible
        // to get entire widget on screen
        var offsetDiffDown = rect.bottom - innerHeightOrClientHeight;
        var offsetDiffUp = rect.top;
        var scrollEl = Utils.getScrollParent(el);
        if (scrollEl !== null) {
          var prevScroll = scrollEl.scrollTop;
          if (rect.top < 0 && distance < 0) {
            // moving up
            if (el.offsetHeight > innerHeightOrClientHeight) {
              scrollEl.scrollTop += distance;
            } else {
              scrollEl.scrollTop += Math.abs(offsetDiffUp) > Math.abs(distance) ? distance : offsetDiffUp;
            }
          } else if (distance > 0) {
            // moving down
            if (el.offsetHeight > innerHeightOrClientHeight) {
              scrollEl.scrollTop += distance;
            } else {
              scrollEl.scrollTop += offsetDiffDown > distance ? distance : offsetDiffDown;
            }
          }
          // move widget y by amount scrolled
          ui.position.top += scrollEl.scrollTop - prevScroll;
        }
      }
    }
  };

  /**
  * @class GridStackDragDropPlugin
  * Base class for drag'n'drop plugin.
  */
  function GridStackDragDropPlugin(grid) {
    this.grid = grid;
  }

  GridStackDragDropPlugin.registeredPlugins = [];

  GridStackDragDropPlugin.registerPlugin = function(pluginClass) {
    GridStackDragDropPlugin.registeredPlugins.push(pluginClass);
  };

  GridStackDragDropPlugin.prototype.resizable = function(el, opts) {
    return this;
  };

  GridStackDragDropPlugin.prototype.draggable = function(el, opts) {
    return this;
  };

  GridStackDragDropPlugin.prototype.droppable = function(el, opts) {
    return this;
  };

  GridStackDragDropPlugin.prototype.isDroppable = function(el) {
    return false;
  };

  GridStackDragDropPlugin.prototype.on = function(el, eventName, callback) {
    return this;
  };


  var idSeq = 0;

  var GridStackEngine = function(column, onchange, float, maxRow, items) {
    this.column = column || 12;
    this.float = float || false;
    this.maxRow = maxRow || 0;

    this.nodes = items || [];
    this.onchange = onchange || function() {};

    this._addedNodes = [];
    this._removedNodes = [];
    this._batchMode = false;
  };

  GridStackEngine.prototype.batchUpdate = function() {
    if (this._batchMode) return;
    this._batchMode = true;
    this._prevFloat = this.float;
    this.float = true; // let things go anywhere for now... commit() will restore and possibly reposition
  };

  GridStackEngine.prototype.commit = function() {
    if (!this._batchMode) return;
    this._batchMode = false;
    this.float = this._prevFloat;
    delete this._prevFloat;
    this._packNodes();
    this._notify();
  };

  // For Meteor support: https://github.com/gridstack/gridstack.js/pull/272
  GridStackEngine.prototype.getNodeDataByDOMEl = function(el) {
    return this.nodes.find(function(n) { return el.get(0) === n.el.get(0); });
  };

  GridStackEngine.prototype._fixCollisions = function(node) {
    var self = this;
    this._sortNodes(-1);

    var nn = node;
    var hasLocked = Boolean(this.nodes.find(function(n) { return n.locked; }));
    if (!this.float && !hasLocked) {
      nn = {x: 0, y: node.y, width: this.column, height: node.height};
    }
    while (true) {
      var collisionNode = this.nodes.find(Utils._collisionNodeCheck, {node: node, nn: nn});
      if (!collisionNode) { return; }
      this.moveNode(collisionNode, collisionNode.x, node.y + node.height,
        collisionNode.width, collisionNode.height, true);
    }
  };

  GridStackEngine.prototype.isAreaEmpty = function(x, y, width, height) {
    var nn = {x: x || 0, y: y || 0, width: width || 1, height: height || 1};
    var collisionNode = this.nodes.find(function(n) {
      return Utils.isIntercepted(n, nn);
    });
    return !collisionNode;
  };

  GridStackEngine.prototype._sortNodes = function(dir) {
    this.nodes = Utils.sort(this.nodes, dir, this.column);
  };

  GridStackEngine.prototype._packNodes = function() {
    this._sortNodes();

    if (this.float) {
      this.nodes.forEach(function(n, i) {
        if (n._updating || n._packY === undefined || n.y === n._packY) {
          return;
        }

        var newY = n.y;
        while (newY >= n._packY) {
          var collisionNode = this.nodes
            .slice(0, i)
            .find(Utils._didCollide, {n: n, newY: newY});

          if (!collisionNode) {
            n._dirty = true;
            n.y = newY;
          }
          --newY;
        }
      }, this);
    } else {
      this.nodes.forEach(function(n, i) {
        if (n.locked) { return; }
        while (n.y > 0) {
          var newY = n.y - 1;
          var canBeMoved = i === 0;

          if (i > 0) {
            var collisionNode = this.nodes
              .slice(0, i)
              .find(Utils._didCollide, {n: n, newY: newY});
            canBeMoved = collisionNode === undefined;
          }

          if (!canBeMoved) { break; }
          // Note: must be dirty (from last position) for GridStack::OnChange CB to update positions
          // and move items back. The user 'change' CB should detect changes from the original
          // starting position instead.
          n._dirty = (n.y !== newY);
          n.y = newY;
        }
      }, this);
    }
  };

  GridStackEngine.prototype._prepareNode = function(node, resizing) {
    node = node || {};
    // if we're missing position, have the grid position us automatically (before we set them to 0,0)
    if (node.x === undefined || node.y === undefined || node.x === null || node.y === null) {
      node.autoPosition = true;
    }

    // assign defaults for missing required fields
    var defaults = {width: 1, height: 1, x: 0, y: 0};
    node = Utils.defaults(node, defaults);

    // convert any strings over
    node.x = parseInt(node.x);
    node.y = parseInt(node.y);
    node.width = parseInt(node.width);
    node.height = parseInt(node.height);
    node.autoPosition = node.autoPosition || false;
    node.noResize = node.noResize || false;
    node.noMove = node.noMove || false;

    // check for NaN (in case messed up strings were passed. can't do parseInt() || defaults.x above as 0 is valid #)
    if (Number.isNaN(node.x))      { node.x = defaults.x; node.autoPosition = true; }
    if (Number.isNaN(node.y))      { node.y = defaults.y; node.autoPosition = true; }
    if (Number.isNaN(node.width))  { node.width = defaults.width; }
    if (Number.isNaN(node.height)) { node.height = defaults.height; }

    if (node.width > this.column) {
      node.width = this.column;
    } else if (node.width < 1) {
      node.width = 1;
    }

    if (node.height < 1) {
      node.height = 1;
    }

    if (node.x < 0) {
      node.x = 0;
    }

    if (node.x + node.width > this.column) {
      if (resizing) {
        node.width = this.column - node.x;
      } else {
        node.x = this.column - node.width;
      }
    }

    if (node.y < 0) {
      node.y = 0;
    }

    return node;
  };

  GridStackEngine.prototype._notify = function() {
    if (this._batchMode) { return; }
    var args = Array.prototype.slice.call(arguments, 0);
    args[0] = (args[0] === undefined ? [] : (Array.isArray(args[0]) ? args[0] : [args[0]]) );
    args[1] = (args[1] === undefined ? true : args[1]);
    var dirtyNodes = args[0].concat(this.getDirtyNodes());
    this.onchange(dirtyNodes, args[1]);
  };

  GridStackEngine.prototype.cleanNodes = function() {
    if (this._batchMode) { return; }
    this.nodes.forEach(function(n) { delete n._dirty; });
  };

  GridStackEngine.prototype.getDirtyNodes = function(verify) {
    // compare original X,Y,W,H (or entire node?) instead as _dirty can be a temporary state
    if (verify) {
      var dirtNodes = [];
      this.nodes.forEach(function (n) {
        if (n._dirty) {
          if (n.y === n._origY && n.x === n._origX && n.width === n._origW && n.height === n._origH) {
            delete n._dirty;
          } else {
            dirtNodes.push(n);
          }
        }
      });
      return dirtNodes;
    }

    return this.nodes.filter(function(n) { return n._dirty; });
  };

  GridStackEngine.prototype.addNode = function(node, triggerAddEvent) {
    node = this._prepareNode(node);

    if (node.maxWidth !== undefined) { node.width = Math.min(node.width, node.maxWidth); }
    if (node.maxHeight !== undefined) { node.height = Math.min(node.height, node.maxHeight); }
    if (node.minWidth !== undefined) { node.width = Math.max(node.width, node.minWidth); }
    if (node.minHeight !== undefined) { node.height = Math.max(node.height, node.minHeight); }

    node._id = node._id || ++idSeq;

    if (node.autoPosition) {
      this._sortNodes();

      for (var i = 0;; ++i) {
        var x = i % this.column;
        var y = Math.floor(i / this.column);
        if (x + node.width > this.column) {
          continue;
        }
        if (!this.nodes.find(Utils._isAddNodeIntercepted, {x: x, y: y, node: node})) {
          node.x = x;
          node.y = y;
          delete node.autoPosition; // found our slot
          break;
        }
      }
    }

    this.nodes.push(node);
    if (triggerAddEvent) {
      this._s.push(node);
    }

    this._fixCollisions(node);
    this._packNodes();
    this._notify();
    return node;
  };

  GridStackEngine.prototype.removeNode = function(node, detachNode) {
    detachNode = (detachNode === undefined ? true : detachNode);
    this._removedNodes.push(node);
    node._id = null; // hint that node is being removed
    this.nodes = Utils.without(this.nodes, node);
    this._packNodes();
    this._notify(node, detachNode);
  };

  GridStackEngine.prototype.removeAll = function(detachNode) {
    delete this._layouts;
    if (this.nodes.length === 0) { return; }
    detachNode = (detachNode === undefined ? true : detachNode);
    this.nodes.forEach(function(n) { n._id = null; }); // hint that node is being removed
    this._removedNodes = this.nodes;
    this.nodes = [];
    this._notify(this._removedNodes, detachNode);
  };

  GridStackEngine.prototype.canMoveNode = function(node, x, y, width, height) {
    if (!this.isNodeChangedPosition(node, x, y, width, height)) {
      return false;
    }
    var hasLocked = Boolean(this.nodes.find(function(n) { return n.locked; }));

    if (!this.maxRow && !hasLocked) {
      return true;
    }

    var clonedNode;
    var clone = new GridStackEngine(
      this.column,
      null,
      this.float,
      0,
      this.nodes.map(function(n) {
        if (n === node) {
          clonedNode = $.extend({}, n);
          return clonedNode;
        }
        return $.extend({}, n);
      }));

    if (!clonedNode) {  return true;}

    clone.moveNode(clonedNode, x, y, width, height);

    var res = true;

    if (hasLocked) {
      res &= !Boolean(clone.nodes.find(function(n) {
        return n !== clonedNode && Boolean(n.locked) && Boolean(n._dirty);
      }));
    }
    if (this.maxRow) {
      res &= clone.getGridHeight() <= this.maxRow;
    }

    return res;
  };

  GridStackEngine.prototype.canBePlacedWithRespectToHeight = function(node) {
    if (!this.maxRow) {
      return true;
    }

    var clone = new GridStackEngine(
      this.column,
      null,
      this.float,
      0,
      this.nodes.map(function(n) { return $.extend({}, n); }));
    clone.addNode(node);
    return clone.getGridHeight() <= this.maxRow;
  };

  GridStackEngine.prototype.isNodeChangedPosition = function(node, x, y, width, height) {
    if (typeof x !== 'number') { x = node.x; }
    if (typeof y !== 'number') { y = node.y; }
    if (typeof width !== 'number') { width = node.width; }
    if (typeof height !== 'number') { height = node.height; }

    if (node.maxWidth !== undefined) { width = Math.min(width, node.maxWidth); }
    if (node.maxHeight !== undefined) { height = Math.min(height, node.maxHeight); }
    if (node.minWidth !== undefined) { width = Math.max(width, node.minWidth); }
    if (node.minHeight !== undefined) { height = Math.max(height, node.minHeight); }

    if (node.x === x && node.y === y && node.width === width && node.height === height) {
      return false;
    }
    return true;
  };

  GridStackEngine.prototype.moveNode = function(node, x, y, width, height, noPack) {
    if (typeof x !== 'number') { x = node.x; }
    if (typeof y !== 'number') { y = node.y; }
    if (typeof width !== 'number') { width = node.width; }
    if (typeof height !== 'number') { height = node.height; }

    if (node.maxWidth !== undefined) { width = Math.min(width, node.maxWidth); }
    if (node.maxHeight !== undefined) { height = Math.min(height, node.maxHeight); }
    if (node.minWidth !== undefined) { width = Math.max(width, node.minWidth); }
    if (node.minHeight !== undefined) { height = Math.max(height, node.minHeight); }

    if (node.x === x && node.y === y && node.width === width && node.height === height) {
      return node;
    }

    var resizing = node.width !== width;
    node._dirty = true;

    node.x = x;
    node.y = y;
    node.width = width;
    node.height = height;

    node.lastTriedX = x;
    node.lastTriedY = y;
    node.lastTriedWidth = width;
    node.lastTriedHeight = height;

    node = this._prepareNode(node, resizing);

    this._fixCollisions(n    if (!noPack) {
      this._packNodes();
      this._notify();
    }
    return node;
  };

  GridStackEngine.prototype.getGridHeight = function() {
    return this.nodes.reduce(function(memo, n) { return Math.max(memo, n.y + n.height); }, 0);
  };

  GridStackEngine.prototype.beginUpdate = function(node) {
    if (node._updating) return;
    node._updating = true;
    this.nodes.forEach(function(n) { n._packY = n.y; });
  };

  GridStackEngine.prototype.endUpdate = function() {
    var n = this.nodes.find(function(n) { return n._updating; });
    if (n) {
      n._updating = false;
      this.nodes.forEach(function(n) { delete n._packY; });
    }
  };

  /**
   * Construct a grid from the given element and options
   * @param {GridStackElement} el
   * @param {GridstackOptions} opts
   */
  var GridStack = function(el, opts) {
    var self = this;
    var oneColumnMode, _prevColumn, isAutoCellHeight;

    opts = opts || {};

    this.container = $(el);

    obsoleteOpts(opts, 'width', 'column', 'v0.5.3');
    obsoleteOpts(opts, 'height', 'maxRow', 'v0.5.3');
    obsoleteOptsDel(opts, 'oneColumnModeClass', 'v0.6.3', '. Use class `.grid-stack-1` instead');

    // container attributes
    obsoleteAttr(this.container, 'data-gs-width', 'data-gs-column', 'v0.5.3');
    obsoleteAttr(this.container, 'data-gs-height', 'data-gs-max-row', 'v0.5.3');

    opts.itemClass = opts.itemClass || 'grid-stack-item';
    var isNested = this.container.closest('.' + opts.itemClass).length > 0;

    this.opts = Utils.defaults(opts, {
      column: parseInt(this.container.attr('data-gs-column')) || 12,
      maxRow: parseInt(this.container.attr('data-gs-max-row')) || 0,
      itemClass: 'grid-stack-item',
      placeholderClass: 'grid-stack-placeholder',
      placeholderText: '',
      handle: '.grid-stack-item-content',
      handleClass: null,
      cellHeight: 60,
      verticalMargin: 20,
      auto: true,
      minWidth: 768,
      float: false,
      staticGrid: false,
      _class: 'grid-stack-instance-' + (Math.random() * 10000).toFixed(0),
      animate: Boolean(this.container.attr('data-gs-animate')) || false,
      alwaysShowResizeHandle: opts.alwaysShowResizeHandle || false,
      resizable: Utils.defaults(opts.resizable || {}, {
        autoHide: !(opts.alwaysShowResizeHandle || false),
        handles: 'se'
      }),
      draggable: Utils.defaults(opts.draggable || {}, {
        handle: (opts.handleClass ? '.' + opts.handleClass : (opts.handle ? opts.handle : '')) ||
          '.grid-stack-item-content',
        scroll: false,
        appendTo: 'body'
      }),
      disableDrag: opts.disableDrag || false,
      disableResize: opts.disableResize || false,
      rtl: 'auto',
      removable: false,
      removableOptions: Utils.defaults(opts.removableOptions || {}, {
        accept: '.' + opts.itemClass
      }),
      removeTimeout: 2000,
      verticalMarginUnit: 'px',
      cellHeightUnit: 'px',
      disableOneColumnMode: opts.disableOneColumnMode || false,
      oneColumnModeDomSort: opts.oneColumnModeDomSort,
      ddPlugin: null
    });

    if (this.opts.ddPlugin === false) {
      this.opts.ddPlugin = GridStackDragDropPlugin;
    } else if (this.opts.ddPlugin === null) {
      this.opts.ddPlugin = GridStackDragDropPlugin.registeredPlugins[0] || GridStackDragDropPlugin;
    }

    this.dd = new this.opts.ddPlugin(this);

    if (this.opts.rtl === 'auto') {
      this.opts.rtl = this.container.css('direction') === 'rtl';
    }

    if (this.opts.rtl) {
      this.container.addClass('grid-stack-rtl');
    }

    this.opts.isNested = isNested;

    isAutoCellHeight = (this.opts.cellHeight === 'auto');
    if (isAutoCellHeight) {
      // make the cell square initially
      self.cellHeight(self.cellWidth(), true);
    } else {
      this.cellHeight(this.opts.cellHeight, true);
    }
    this.verticalMargin(this.opts.verticalMargin, true);

    this.container.addClass(this.opts._class);

    this._setStaticClass();

    if (isNested) {
      this.container.addClass('grid-stack-nested');
    }

    this._initStyles();

   is.grid = new GridStackEngine(this.opts.column, function(nodes, detachNode) {
      detachNode = (detachNode === undefined ? true : detachNode);
      var maxHeight = 0;
      this.nodes.forEach(function(n) {
        maxHeight = Math.max(maxHeight, n.y + n.height);
      });
      nodes.forEach(function(n) {
        if (detachNode && n._id === null) {
          if (n.el) {
            n.el.remove();
          }
        } else {
          n.el
            .attr('data-gs-x', n.x)
            .attr('data-gs-y', n.y)
            .attr('data-gs-width', n.width)
            .attr('data-gs-height', n.height);
        }
      });
      self._updateStyles(maxHeight + 10);
    }, this.opts.float, this.opts.maxRow);

    if (this.opts.auto) {
      var elements = [];
      var _this = this;
      this.container.children('.' + this.opts.itemClass + ':not(.' + this.opts.placeholderClass + ')')
        .each(function(index, el) {
          el = $(el);
          var x = parseInt(el.attr('data-gs-x'));
          var y = parseInt(el.attr('data-gs-y'));
          elements.push({
            el: el,
            // if x,y are missing (autoPosition) add them to end of list - but keep their respective DOM order
            i: (Number.isNaN(x) ? 1000 : x) + (Number.isNaN(y) ? 1000 : y) * _this.opts.column
          });
        });
      Utils.sortBy(elements, function(x) { return x.i; }).forEach(function(item) {
        this._prepareElement(item.el);
      }, this);
    }
    this.grid._saveInitial(); // initial start of items

    this.setAnimation(this.opts.animate);

    this.placeholder = $(
      '<div class="' + this.opts.placeholderClass + ' ' + this.opts.itemClass + '">' +
      '<div class="placeholder-content">' + this.opts.placeholderText + '</div></div>').hide();

    this._updateContainerHeight();

    this._updateHeightsOnResize = Utils.throttle(function() {
      self.cellHeight(self.cellWidth(), false);
    }, 100);

    /**
     * called when we are being resized - check if the one Column Mode needs to be turned on/off
     * and remember the prev columns we used.
     */
    this.onResizeHandler = function() {
      if (isAutoCellHeight) {
        self._updateHeightsOnResize();
      }

      if (self.opts.staticGrid) { return; }

      if (!self.opts.disableOneColumnMode && (window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) <= self.opts.minWidth) {
        if (self.oneColumnMode) {  return; }
        self.oneColumnMode = true;
        self.setColumn(1);
      } else {
        if (!self.oneColumnMode) { return; }
        self.oneColumnMode = false;
        self.setColumn(self._prevColumn);
      }
    };

    $(window).resize(this.onResizeHandler);
    this.onResizeHandler();

    if (!self.opts.staticGrid && typeof self.opts.removable === 'string') {
      var trashZone = $(self.opts.removable);
      if (!this.dd.isDroppable(trashZone)) {
        this.dd.droppable(trashZone, self.opts.removableOptions);
      }
      this.dd
        .on(trashZone, 'dropover', function(event, ui) {
          var el = $(ui.draggable);
          var node = el.data('_gridstack_node');
          if (!node || node._grid !== self) {
            return;
          }
          el.data('inTrashZone', true);
          self._setupRemovingTimeout(el);
        })
        .on(trashZone, 'dropout', function(event, ui) {
          var el = $(ui.draggable);
          var node = el.data('_gridstack_node');
          if (!node || node._grid !== self) {
            return;
          }
          el.data('inTrashZone', false);
          self._clearRemovingTimeout(el);
        });
    }

    if (!self.opts.staticGrid && self.opts.acceptWidgets) {
      var draggingElement = null;

      var onDrag = function(event, ui) {
        var el = draggingElement;
        var node = el.data('_gridstack_node');
        var pos = self.getCellFromPixel({left: event.pageX, top: event.pageY}, true);
        var x = Math.max(0, pos.x);
        var y = Math.max(0, pos.y);
        if (!node._added) {
          node._added = true;

          node.el = el;
          node.autoPosition = true;
          node.x = x;
          node.y = y;
          self.grid.cleanNodes();
          self.grid.beginUpdate(node);
          self.grid.addNode(node);

          self.container.append(self.placeholder);
          self.placeholder
            .attr('data-gs-x', node.x)
            .attr('data-gs-y', node.y)
            .attr('data-gs-width', node.width)
            .attr('data-gs-height', node.height)
            .show();
          node.el = self.placeholder;
          node._beforeDragX = node.x;
          node._beforeDragY = node.y;

          self._updateContainerHeight();
        }
        if (!self.grid.canMoveNode(node, x, y)) {
          return;
        }
        self.grid.moveNode(node, x, y);
        self._updateContainerHeight();
      };

      this.dd
        .droppable(self.container, {
          accept: function(el) {
            el = $(el);
            var node = el.data('_gridstack_node');
            if (node && node._grid === self) {
              return false;
            }
            return el.is(self.opts.acceptWidgets === true ? '.grid-stack-item' : self.opts.acceptWidgets);
          }
        })
        .on(self.container, 'dropover', function(event, ui) {
          var el = $(ui.draggable);
          var width, height;

          // see if we already have a node with widget/height and check for attributes
          var origNode = el.data('_gridstack_node');
          if (!origNode || !origNode.width || !origNode.height) {
            var w = parseInt(el.attr('data-gs-width'));
            if (w > 0) { origNode = origNode || {}; origNode.width = w; }
            var h = parseInt(el.attr('data-gs-height'));
            if (h > 0) { origNode = origNode || {}; origNode.height = h; }
          }

          // if not calculate the grid size based on element outer size
          // height: Each row is cellHeight + verticalMargin, until last one which has no margin below
          var cellWidth = self.cellWidth();
          var cellHeight = self.cellHeight();
          var verticalMargin = self.opts.verticalMargin;
          width = origNode && origNode.width ? origNode.width : Math.ceil(el.outerWidth() / cellWidth);
          height = origNode && origNode.height ? origNode.height : Math.round((el.outerHeight() + verticalMargin) / (cellHeight + verticalMargin));

          draggingElement = el;

          var node = self.grid._prepareNode({width: width, height: height, _added: false, _temporary: true});
          node.isOutOfGrid = true;
          el.data('_gridstack_node', node);
          el.data('_gridstack_node_orig', origNode);

          el.on('drag', onDrag);
          return false; // prevent parent from receiving msg (which may be grid as well)
        })
        .on(self.container, 'dropout', function(event, ui) {
          // jquery-ui bug. Must verify widget is being dropped out
          // check node variable that gets set when widget is out of grid
          var el = $(ui.draggable);
          if (!el.data('_gridstack_node')) {
            return;
          }
          var node = el.data('_gridstack_node');
          if (!node.isOutOfGrid) {
            return;
          }
          el.unbind('drag', onDrag);
          node.el = null;
          self.grid.removeNode(node);
          self.placeholder.detach();
          self._updateContainerHeight();
          el.data('_gridstack_node', el.data('_gridstack_node_orig'));
          return false; // prevent parent from receiving msg (which may be grid as well)
        })
        .on(self.container, 'drop', function(event, ui) {
          self.placeholder.detach();

          var node = $(ui.draggable).data('_gridstack_node');
          node.isOutOfGrid = false;
          node._grid = self;
          var el = $(ui.draggable).clone(false);
          el.data('_gridstack_node', node);
          var originalNode = $(ui.draggable).data('_gridstack_node_orig');
          if (originalNode !== undefined && originalNode._grid !== undefined) {
            originalNode._grid._triggerRemoveEvent();
          }
          $(ui.helper).remove();
          node.el = el;
          self.placeholder.hide();
          Utils.removePositioningStyles(el);
          el.find('div.ui-resizable-handle').remove();

          el
            .attr('data-gs-x', node.x)
            .attr('data-gs-y', node.y)
            .attr('data-gs-width', node.width)
            .attr('data-gs-height', node.height)
            .addClass(self.opts.itemClass)
            .enableSelection()
            .removeData('draggable')
            .removeClass('ui-draggable ui-draggable-dragging ui-draggable-disabled')
            .unbind('drag', onDrag);
          self.container.append(el);
          self._prepareElementsByNode(el, node);
          self._updateContainerHeight();
          self.grid._addedNodes.push(node);
          self._triggerAddEvent();
          self._triggerChangeEvent();

          self.grid.endUpdate();
          $(ui.draggable).unbind('drag', onDrag);
          $(ui.draggable).removeData('_gridstack_node');
          $(ui.draggable).removeData('_gridstack_node_orig');
          self.container.trigger('dropped', [originalNode, node]);
          return false; // prevent parent from receiving msg (which may be grid as well)
        });
    }
  };

  GridStack.prototype._triggerChangeEvent = function(/*forceTrigger*/) {
    if (this.grid._batchMode) { return; }
    var elements = this.grid.getDirtyNodes(true); // verify they really changed
    if (elements && elements.length) {
      this.grid._layoutsNodesChange(elements);
      this.container.trigger('change', [elements]);
    }
    this.grid._saveInitial(); // we called, now reset initial values & dirty flags
  };

  GridStack.prototype._triggerAddEvent = function() {
    if (this.grid._batchMode) { return; }
    if (this.grid._addedNodes && this.grid._addedNodes.length > 0) {
      this.grid._layoutsNodesChange(this.grid._addedNodes);
      // prevent added nodes from also triggering 'change' event (which is called next)
      this.grid._addedNodes.forEach(function (n) { delete n._dirty; });
      this.container.trigger('added', [this.grid._addedNodes]);
      this.grid._addedNodes = [];
    }
  };

  GridStack.prototype._triggerRemoveEvent = function() {
    if (this.grid._batchMode) { return; }
    if (this.grid._removedNodes && this.grid._removedNodes.length > 0) {
      this.container.trigger('removed', [this.grid._removedNodes]);
      this.grid._removedNodes = [];
    }
  };

  GridStack.prototype._initStyles = function() {
    if (this._stylesId) {
      Utils.removeStylesheet(this._stylesId);
    }
    this._stylesId = 'gridstack-style-' + (Math.random() * 100000).toFixed();
    // insert style to parent (instead of 'head') to support WebComponent
    this._styles = Utils.createStylesheet(this._stylesId, this.container.get(0).parentNode);
    if (this._styles !== null) {
      this._styles._max = 0;
    }
  };

  GridStack.prototype._updateStyles = function(maxHeight) {
    if (this._styles === null || this._styles === undefined) {
      return;
    }

    var prefix = '.' + this.opts._class + ' .' + this.opts.itemClass;
    var self = this;
    var getHeight;

    if (maxHeight === undefined) {
      maxHeight = this._styles._max;
    }

    this._initStyles();
    this._updateContainerHeight();
    if (!this.opts.cellHeight) { // The rest will be handled by CSS
      return ;
    }
    if (this._styles._max !== 0 && maxHeight <= this._styles._max) { // Keep this._styles._max increasing
      return ;
    }

    if (!this.opts.verticalMargin || this.opts.cellHeightUnit === this.opts.verticalMarginUnit) {
      getHeight = function(nbRows, nbMargins) {
        return (self.opts.cellHeight * nbRows + self.opts.verticalMargin * nbMargins) +
          self.opts.cellHeightUnit;
      };
    } else {
      getHeight = function(nbRows, nbMargins) {
        if (!nbRows || !nbMargins) {
          return (self.opts.cellHeight * nbRows + self.opts.verticalMargin * nbMargins) +
            self.opts.cellHeightUnit;
        }
        return 'calc(' + ((self.opts.cellHeight * nbRows) + self.opts.cellHeightUnit) + ' + ' +
          ((self.opts.verticalMargin * nbMargins) + self.opts.verticalMarginUnit) + ')';
      };
    }

    if (this._styles._max === 0) {
      Utils.insertCSSRule(this._styles, prefix, 'min-height: ' + getHeight(1, 0) + ';', 0);
    }

    if (maxHeight > this._styles._max) {
      for (var i = this._styles._max; i < maxHeight; ++i) {
        Utils.insertCSSRule(this._styles,
          prefix + '[data-gs-height="' + (i + 1) + '"]',
          'height: ' + getHeight(i + 1, i) + ';',
          i
        );
        Utils.insertCSSRule(this._styles,
          prefix + '[data-gs-min-height="' + (i + 1) + '"]',
          'min-height: ' + getHeight(i + 1, i) + ';',
          i
        );
        Utils.insertCSSRule(this._styles,
          prefix + '[data-gs-max-height="' + (i + 1) + '"]',
          'max-height: ' + getHeight(i + 1, i) + ';',
          i
        );
        Utils.insertCSSRule(this._styles,
          prefix + '[data-gs-y="' + i + '"]',
          'top: ' + getHeight(i, i) + ';',
          i
        );
      }
      this._styles._max = maxHeight;
    }
  };

  GridStack.prototype._updateContainerHeight = function() {
    if (this.grid._batchMode) { return; }
    var height = this.grid.getGridHeight();
    // check for css min height. Each row is cellHeight + verticalMargin, until last one which has no margin below
    var cssMinHeight = parseInt(this.container.css('min-height'));
    if (cssMinHeight > 0) {
      var verticalMargin = this.opts.verticalMargin;
      var minHeight =  Math.round((cssMinHeight + verticalMargin) / (this.cellHeight() + verticalMargin));
      if (height < minHeight) {
        height = minHeight;
      }
    }
    this.container.attr('data-gs-current-height', height);
    if (!this.opts.cellHeight) {
      return ;
    }
    if (!this.opts.verticalMargin) {
      this.container.css('height', (height * (this.opts.cellHeight)) + this.opts.cellHeightUnit);
    } else if (this.opts.cellHeightUnit === this.opts.verticalMarginUnit) {
      this.container.css('height', (height * (this.opts.cellHeight + this.opts.verticalMargin) -
        this.opts.verticalMargin) + this.opts.cellHeightUnit);
    } else {
      this.container.css('height', 'calc(' + ((height * (this.opts.cellHeight)) + this.opts.cellHeightUnit) +
        ' + ' + ((height * (this.opts.verticalMargin - 1)) + this.opts.verticalMarginUnit) + ')');
    }
  };

  GridStack.prototype._setupRemovingTimeout = function(el) {
    var self = this;
    var node = $(el).data('_gridstack_node');

    if (node._removeTimeout || !self.opts.removable) {
      return;
    }
    node._removeTimeout = setTimeout(function() {
      el.addClass('grid-stack-item-removing');
      node._isAboutToRemove = true;
    }, self.opts.removeTimeout);
  };

  GridStack.prototype._clearRemovingTimeout = function(el) {
    var node = $(el).data('_gridstack_node');

    if (!node._removeTimeout) {
      return;
    }
    clearTimeout(node._removeTimeout);
    node._removeTimeout = null;
    el.removeClass('grid-stack-item-removing');
    node._isAboutToRemove = false;
  };

  GridStack.prototype._prepareElementsByNode = function(el, node) {
    var self = this;

    var cellWidth;
    var cellHeight;

    var dragOrResize = function(event, ui) {
      var x = Math.round(ui.position.left / cellWidth);
      var y = Math.floor((ui.position.top + cellHeight / 2) / cellHeight);
      var width;
      var height;

      if (event.type !== 'drag') {
        width = Math.round(ui.size.width / cellWidth);
        height = Math.round(ui.size.height / cellHeight);
      }

      if (event.type === 'drag') {
        var distance = ui.position.top - node._prevYPix;
        node._prevYPix = ui.position.top;
        Utils.updateScrollPosition(el[0], ui, distance);
        if (el.data('inTrashZone') || x < 0 || x >= self.grid.column || y < 0 ||
          (!self.grid.float && y > self.grid.getGridHeight())) {
          if (!node._temporaryRemoved) {
            if (self.opts.removable === true) {
              self._setupRemovingTimeout(el);
            }

            x = node._beforeDragX;
            y = node._beforeDragY;

            self.placeholder.detach();
            self.placeholder.hide();
            self.grid.removeNode(node);
            self._updateContainerHeight();

            node._temporaryRemoved = true;
          } else {
            return;
          }
        } else {
          self._clearRemovingTimeout(el);

          if (node._temporaryRemoved) {
            self.grid.addNode(node);
            self.placeholder
              .attr('data-gs-x', x)
              .attr('data-gs-y', y)
              .attr('data-gs-width', width)
              .attr('data-gs-height', height)
              .show();
            self.container.append(self.placeholder);
            node.el = self.placeholder;
            node._temporaryRemoved = false;
          }
        }
      } else if (event.type === 'resize')  {
        if (x < 0) {
          return;
        }
      }
      // width and height are undefined if not resizing
      var lastTriedWidth = width !== undefined ? width : node.lastTriedWidth;
      var lastTriedHeight = height !== undefined ? height : node.lastTriedHeight;
      if (!self.grid.canMoveNode(node, x, y, width, height) ||
        (node.lastTriedX === x && node.lastTriedY === y &&
        node.lastTriedWidth === lastTriedWidth && node.lastTriedHeight === lastTriedHeight)) {
        return;
      }
      node.lastTriedX = x;
      node.lastTriedY = y;
      node.lastTriedWidth = width;
      node.lastTriedHeight = height;
      self.grid.moveNode(node, x, y, width, height);
      self._updateContainerHeight();

      if (event.type === 'resize')  {
        $(event.target).trigger('gsresize', node);
      }
    };

    var onStartMoving = function(event, ui) {
      self.container.append(self.placeholder);
      var o = $(this);
      self.grid.cleanNodes();
      self.grid.beginUpdate(node);
      cellWidth = self.cellWidth();
      var strictCellHeight = self.cellHeight();
      // TODO: cellHeight = cellHeight() causes issue (i.e. remove strictCellHeight above) otherwise
      // when sizing up we jump almost right away to next size instead of half way there. Not sure
      // why as we don't use ceil() in many places but round() instead.
      cellHeight = self.container.height() / parseInt(self.container.attr('data-gs-current-height'));
      self.placeholder
        .attr('data-gs-x', o.attr('data-gs-x'))
        .attr('data-gs-y', o.attr('data-gs-y'))
        .attr('data-gs-width', o.attr('data-gs-width'))
        .attr('data-gs-height', o.attr('data-gs-height'))
        .show();
      node.el = self.placeholder;
      node._beforeDragX = node.x;
      node._beforeDragY = node.y;
      node._prevYPix = ui.position.top;
      var minHeight = (node.minHeight || 1);
      var verticalMargin = self.opts.verticalMargin;

      // mineHeight - Each row is cellHeight + verticalMargin, until last one which has no margin below
      self.dd.resizable(el, 'option', 'minWidth', cellWidth * (node.minWidth || 1));
      self.dd.resizable(el, 'option', 'minHeight', (strictCellHeight * minHeight) + (minHeight - 1) * verticalMargin);

      if (event.type === 'resizestart') {
        o.find('.grid-stack-item').trigger('resizestart');
      }
    };

    var onEndMoving = function(event, ui) {
      var o = $(this);
      if (!o.data('_gridstack_node')) {
        return;
      }

      // var forceNotify = false; what is the point of calling 'change' event with no data, when the 'removed' event is already called ?
      self.placeholder.detach();
      node.el = o;
      self.placeholder.hide();

      if (node._isAboutToRemove) {
        // forceNotify = true;
        var gridToNotify = el.data('_gridstack_node')._grid;
        gridToNotify._triggerRemoveEvent();
        el.removeData('_gridstack_node');
        el.remove();
      } else {
        self._clearRemovingTimeout(el);
        if (!node._temporaryRemoved) {
          Utils.removePositioningStyles(o);
          o
            .attr('data-gs-x', node.x)
            .attr('data-gs-y', node.y)
            .attr('data-gs-width', node.width)
            .attr('data-gs-height', node.height);
        } else {
          Utils.removePositioningStyles(o);
          o
            .attr('data-gs-x', node._beforeDragX)
            .attr('data-gs-y', node._beforeDragY)
            .attr('data-gs-width', node.width)
            .attr('data-gs-height', node.height);
          node.x = node._beforeDragX;
          node.y = node._beforeDragY;
          node._temporaryRemoved = false;
          self.grid.addNode(node);
        }
      }
      self._updateContainerHeight();
      self._triggerChangeEvent(/*forceNotify*/);

      self.grid.endUpdate();

      var nestedGrids = o.find('.grid-stack');
      if (nestedGrids.length && event.type === 'resizestop') {
        nestedGrids.each(function(index, el) {
          $(el).data('gridstack').onResizeHandler();
        });
        o.find('.grid-stack-item').trigger('resizestop');
        o.find('.grid-stack-item').trigger('gsresizestop');
      }
      if (event.type === 'resizestop') {
        self.container.trigger('gsresizestop', o);
      }
    };

    this.dd
      .draggable(el, {
        start: onStartMoving,
        stop: onEndMoving,
        drag: dragOrResize
      })
      .resizable(el, {
        start: onStartMoving,
        stop: onEndMoving,
        resize: dragOrResize
      });

    if (node.noMove || this.opts.disableDrag || this.opts.staticGrid) {
      this.dd.draggable(el, 'disable');
    }

    if (node.noResize || this.opts.disableResize || this.opts.staticGrid) {
      this.dd.resizable(el, 'disable');
    }

    this._writeAttr(el, node);
  };

  GridStack.prototype._prepareElement = function(el, triggerAddEvent) {
    triggerAddEvent = triggerAddEvent !== undefined ? triggerAddEvent : false;
    var self = this;
    el = $(el);

    el.addClass(this.opts.itemClass);
    var node = this._readAttr(el, {el: el, _grid: self});
    node = self.grid.addNode(node, triggerAddEvent);
    el.data('_gridstack_node', node);

    this._prepareElementsByNode(el, node);
  };

  /** call to write any default attributes back to element */
  GridStack.prototype._writeAttr = function(el, node) {
    el = $(el);
    node = node || {};
    // Note: passing null removes the attr in jquery
    if (node.x !== undefined) { el.attr('data-gs-x', node.x); }
    if (node.y !== undefined) { el.attr('data-gs-y', node.y); }
    if (node.width !== undefined) { el.attr('data-gs-width', node.width); }
    if (node.height !== undefined) { el.attr('data-gs-height', node.height); }
    if (node.autoPosition !== undefined) { el.attr('data-gs-auto-position', node.autoPosition ? true : null); }
    if (node.minWidth !== undefined) { el.attr('data-gs-min-width', node.minWidth); }
    if (node.maxWidth !== undefined) { el.attr('data-gs-max-width', node.maxWidth); }
    if (node.minHeight !== undefined) { el.attr('data-gs-min-height', node.minHeight); }
    if (node.maxHeight !== undefined) { el.attr('data-gs-max-height', node.maxHeight); }
    if (node.noResize !== undefined) { el.attr('data-gs-no-resize', node.noResize ? true : null); }
    if (node.noMove !== undefined) { el.attr('data-gs-no-move', node.noMove ? true : null); }
    if (node.locked !== undefined) { el.attr('data-gs-locked', node.locked ? true : null); }
    if (node.resizeHandles !== undefined) { el.attr('data-gs-resize-handles', node.resizeHandles); }
    if (node.id !== undefined) { el.attr('data-gs-id', node.id); }
  };

  /** call to write any default attributes back to element */
  GridStack.prototype._readAttr = function(el, node) {
    el = $(el);
    node = node || {};
    node.x = el.attr('data-gs-x');
    node.y = el.attr('data-gs-y');
    node.width = el.attr('data-gs-width');
    node.height = el.attr('data-gs-height');
    node.autoPosition = Utils.toBool(el.attr('data-gs-auto-position'));
    node.maxWidth = el.attr('data-gs-max-width');
    node.minWidth = el.attr('data-gs-min-width');
    node.maxHeight = el.attr('data-gs-max-height');
    node.minHeight = el.attr('data-gs-min-height');
    node.noResize =toBool(el.attr('data-gs-no-resize'));
    node.noMove = Utils.toBool(el.attr('data-gs-no-move'));
    node.locked = Utils.toBool(el.attr('data-gs-locked'));
    node.resizeHandles = el.attr('data-gs-resize-handles');
    node.id = el.attr('data-gs-id');
    return node;
  };

  GridStack.prototype.setAnimation = function(enable) {
    if (enable) {
      this.container.addClass('grid-stack-animate');
    } else {
      this.container.removeClass('grid-stack-animate');
    }
  };

  GridStack.prototype.addWidget = function(el, node, y, width, height, autoPosition, minWidth, maxWidth, minHeight, maxHeight, id) {

    // new way of calling with an object - make sure all items have been properly initialized
    if (node === undefined || typeof node === 'object') {
      // Tempting to initialize the passed in node with default and valid values, but this break knockout demos
      // as the actual value are filled in when _prepareElement() calls el.attr('data-gs-xyz) before adding the node.
      // node = this.grid._prepareNode(node);
      node = node || {};
    } else {
      // old legacy way of calling with items spelled out - call us back with single object instead (so we can properly initialized values)
      return this.addWidget(el, {x: node, y: y, width: width, height: height, autoPosition: autoPosition,
        minWidth: minWidth, maxWidth: maxWidth, minHeight: minHeight, maxHeight: maxHeight, id: id});
    }

    el = $(el);
    this._writeAttr(el, node);
    this.container.append(el);
    return this.makeWidget(el);
  };

  GridStack.prototype.makeWidget = function(el) {
    el = $(el);
    this._prepareElement(el, true);
    this._updateContainerHeight();
    this._triggerAddEvent();
    this._triggerChangeEvent(true); // trigger any other changes

    return el;
  };

  GridStack.prototype.willItFit = function(x, y, width, height, autoPosition) {
    var node = {x: x, y: y, width: width, height: height, autoPosition: autoPosition};
    return this.grid.canBePlacedWithRespectToHeight(node);
  };

  GridStack.prototype.removeWidget = function(el, detachNode) {
    detachNode = (detachNode === undefined ? true : detachNode);
    el = $(el);
    var node = el.data('_gridstack_node');
    // For Meteor support: https://github.com/gridstack/gridstack.js/pull/272
    if (!node) {
      node = this.grid.getNodeDataByDOMEl(el);
    }

    el.removeData('_gridstack_node');
    this.grid.removeNode(node, detachNode);
    this._triggerRemoveEvent();
    this._triggerChangeEvent(true); // trigger any other changes
  };

  GridStack.prototype.removeAll = function(detachNode) {
    if (detachNode !== false) {
      // remove our data structure before list gets emptied and DOM elements stay behind
      this.grid.nodes.forEach(function(node) { node.el.removeData('_gridstack_node') });
    }
    this.grid.removeAll(detachNode);
    this._triggerRemoveEvent();
  };

  GridStack.prototype.destroy = function(detachGrid) {
    $(window).off('resize', this.onResizeHandler);
    this.disable();
    if (detachGrid !== undefined && !detachGrid) {
      this.removeAll(false);
      this.container.removeData('gridstack');
    } else {
      this.container.remove();
    }
    Utils.removeStylesheet(this._stylesId);
    if (this.grid) {
      this.grid = null;
    }
  };

  GridStack.prototype.resizable = function(el, val) {
    var self = this;
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      node.noResize = !(val || false);
      if (node.noResize) {
        self.dd.resizable(el, 'disable');
      } else {
        self.dd.resizable(el, 'enable');
      }
    });
    return this;
  };

  GridStack.prototype.movable = function(el, val) {
    var self = this;
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      node.noMove = !(val || false);
      if (node.noMove) {
        self.dd.draggable(el, 'disable');
        el.removeClass('ui-draggable-handle     } else {
        self.dd.draggable(el, 'enable');
        el.addClass('ui-draggable-handle');
      }
    });
    return this;
  };

  GridStack.prototype.enableMove = function(doEnable, includeNewWidgets) {
    this.movable(this.container.children('.' + this.opts.itemClass), doEnable);
    if (includeNewWidgets) {
      this.opts.disableDrag = !doEnable;
    }
  };

  GridStack.prototype.enableResize = function(doEnable, includeNewWidgets) {
    this.resizable(this.container.children('.' + this.opts.itemClass), doEnable);
    if (includeNewWidgets) {
      this.opts.disableResize = !doEnable;
    }
  };

  GridStack.prototype.disable = function() {
    this.movable(this.container.children('.' + this.opts.itemClass), false);
    this.resizable(this.container.children('.' + this.opts.itemClass), false);
    this.container.trigger('disable');
  };

  GridStack.prototype.enable = function() {
    this.movable(this.container.children('.' + this.opts.itemClass), true);
    this.resizable(this.container.children('.' + this.opts.itemClass), true);
    this.container.trigger('enable');
  };

  GridStack.prototype.locked = function(el, val) {
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      node.locked = (val || false);
      el.attr('data-gs-locked', node.locked ? 'yes' : null);
    });
    return this;
  };

  GridStack.prototype.maxHeight = function(el, val) {
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      if (!isNaN(val)) {
        node.maxHeight = (val || false);
        el.attr('data-gs-max-height', val);
      }
    });
    return this;
  };

  GridStack.prototype.minHeight = function(el, val) {
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      if (!isNaN(val)) {
        node.minHeight = (val || false);
        el.attr('data-gs-min-height', val);
      }
    });
    return this;
  };

  GridStack.prototype.maxWidth = function(el, val) {
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      if (!isNaN(val)) {
        node.maxWidth = (val || false);
        el.attr('data-gs-max-width', val);
      }
    });
    return this;
  };

  GridStack.prototype.minWidth = function(el, val) {
    el = $(el);
    el.each(function(index, el) {
      el = $(el);
      var node = el.data('_gridstack_node');
      if (!node) { return; }
      if (!isNaN(val)) {
        node.minWidth = (val || false);
        el.attr('data-gs-min-width', val);
      }
    });
    return this;
  };

  GridStack.prototype._updateElement = function(el, callback) {
    el = $(el).first();
    var node = el.data('_gridstack_node');
    if (!node) { return; }
    var self = this;

    self.grid.cleanNodes();
    self.grid.beginUpdate(node);

    callback.call(this, el, node);

    self._updateContainerHeight();
    self._triggerChangeEvent();

    self.grid.endUpdate();
  };

  GridStack.prototype.resize = function(el, width, height) {
    this._updateElement(el, function(el, node) {
      width = (width !== null && width !== undefined) ? width : node.width;
      height = (height !== null && height !== undefined) ? height : node.height;

      this.grid.moveNode(node, node.x, node.y, width, height);
    });
  };

  GridStack.prototype.move = function(el, x, y) {
    this._updateElement(el, function(el, node) {
      x = (x !== null && x !== undefined) ? x : node.x;
      y = (y !== null && y !== undefined) ? y : node.y;

      this.grid.moveNode(node, x, y, node.width, node.height);
    });
  };

  GridStack.prototype.update = function(el, x, y, width, height) {
    this._updateElement(el, function(el, node) {
      x = (x !== null && x !== undefined) ? x : node.x;
      y = (y !== null && y !== undefined) ? y : node.y;
      width = (width !== null && width !== undefined) ? width : node.width;
      height = (height !== null && height !== undefined) ? height : node.height;

      this.grid.moveNode(node, x, y, width, height);
    });
  };

  /**
   * relayout grid items to reclaim any empty space
   */
  GridStack.prototype.compact = function() {
    if (this.grid.nodes.length === 0) { return; }
    this.batchUpdate();
    this.grid._sortNodes();
    var nodes = this.grid.nodes;
    this.grid.nodes = []; // pretend we have no nodes to conflict layout to start with...
    nodes.forEach(function(node) {
      if (!node.noMove && !node.locked) {
        node.autoPosition = true;
      }
      this.grid.addNode(node, false); // 'false' for add event trigger...
      node._dirty = true; // force attr update
    }, this);
    this.commit();
  };

  GridStack.prototype.verticalMargin = function(val, noUpdate) {
    if (val === undefined) {
      return this.opts.verticalMargin;
    }

    var heightData = Utils.parseHeight(val);

    if (this.opts.verticalMarginUnit === heightData.unit && this.opts.maxRow === heightData.height) {
      return ;
    }
    this.opts.verticalMarginUnit = heightData.unit;
    this.opts.verticalMargin = heightData.height;

    if (!noUpdate) {
      this._updateStyles();
    }
  };

  /** set/get the current cell height value */
  GridStack.prototype.cellHeight = function(val, noUpdate) {
    // getter - returns the opts stored height else compute it...
    if (val === undefined) {
      if (this.opts.cellHeight && this.opts.cellHeight !== 'auto') {
        return this.opts.cellHeight;
      }
      // compute the height taking margin into account (each row has margin other than last one)
      var o = this.container.children('.' + this.opts.itemClass).first();
      var height = o.attr('data-gs-height');
      var verticalMargin = this.opts.verticalMargin;
      return Math.round((o.outerHeight() - (height - 1) * verticalMargin) / height);
    }

    // setter - updates the cellHeight value if they changed
    var heightData = Utils.parseHeight(val);
    if (this.opts.cellHeightUnit === heightData.unit && this.opts.cellHeight === heightData.height) {
      return ;
    }
    this.opts.cellHeightUnit = heightData.unit;
    this.opts.cellHeight = heightData.height;

    if (!noUpdate) {
      this._updateStyles();
    }
  };

  GridStack.prototype.cellWidth = function() {
    // TODO: take margin into account ($horizontal_padding in .scss) to make cellHeight='auto' square ? (see 810-many-columns.html)
    return Math.round(this.container.outerWidth() / this.opts.column);
  };

  GridStack.prototype.getCellFromPixel = function(position, useOffset) {
    var containerPos = (useOffset !== undefined && useOffset) ?
      this.container.offset() : this.container.position();
    var relativeLeft = position.left - containerPos.left;
    var relativeTop = position.top - containerPos.top;

    var columnWidth = Math.floor(this.container.width() / this.opts.column);
    var rowHeight = Math.floor(this.container.height() / parseInt(this.container.attr('data-gs-current-height')));

    return {x: Math.floor(relativeLeft / columnWidth), y: Math.floor(relativeTop / rowHeight)};
  };

  GridStack.prototype.batchUpdate = function() {
    this.grid.batchUpdate();
  };

  GridStack.prototype.commit = function() {
    this.grid.commit();
    this._triggerRemoveEvent();
    this._triggerAddEvent();
    this._triggerChangeEvent();
  };

  GridStack.prototype.isAreaEmpty = function(x, y, width, height) {
    return this.grid.isAreaEmpty(x, y, width, height);
  };

  GridStack.prototype.setStatic = function(staticValue) {
    this.opts.staticGrid = (staticValue === true);
    this.enableMove(!staticValue);
    this.enableResize(!staticValue);
    this._setStaticClass();
  };

  GridStack.prototype._setStaticClass = function() {
    var staticClassName = 'grid-stack-static';

    if (this.opts.staticGrid === true) {
      this.container.addClass(staticClassName);
    } else {
      this.container.removeClass(staticClassName);
    }
  };

  /** called whenever a node is added or moved - updates the cached layouts */
  GridStackEngine.prototype._layoutsNodesChange = function(nodes) {
    if (!this._layouts || this._ignoreLayoutsNodeChange) return;
    // remove smaller layouts - we will re-generate those on the fly... larger ones need to update
    this._layouts.forEach(function(layout, column) {
      if (!layout || column === this.column) return;
      if (column < this.column) {
        this._layouts[column] = undefined;
      }
      else {
        // we save the original x,y,w (h isn't cached) to see what actually changed to propagate better.
        // Note: we don't need to check against out of bound scaling/moving as that will be done when using those cache values.
        nodes.forEach(function(node) {
          var n = layout.find(function(l) { return l._id === node._id });
          if (!n) return; // no cache for new nodes. Will use those values.
          var ratio = column / this.column;
          // Y changed, push down same amount
          // TODO: detect doing item 'swaps' will help instead of move (especially in 1 column mode)
          if (node.y !== node._origY) {
            n.y += (node.y - node._origY);
          }
          // X changed, scale from new position
          if (node.x !== node._origX) {
            n.x = Math.round(node.x * ratio);
          }
          // width changed, scale from new width
          if (node.width !== node._origW) {
            n.width = Math.round(node.width * ratio);
          }
          // ...height always carries over from cache
        }, this);
      }
    }, this);
  }

  /**
   * Called to scale the widget width & position up/down based on the column change.
   * Note we store previous layouts (especially original ones) to make it possible to go
   * from say 12 -> 1 -> 12 and get back to where we were.
   *
   * oldColumn: previous number of columns
   * column:    new column number
   * nodes?:    different sorted list (ex: DOM order) instead of current list
   */
  GridStackEngine.prototype._updateNodeWidths = function(oldColumn, column, nodes) {
    if (!this.nodes.length || oldColumn === column) { return; }

    // cache the current layout in case they want to go back (like 12 -> 1 -> 12) as it requires original data
    var copy = [this.nodes.length];
    this.nodes.forEach(function(n, i) {copy[i] = {x: n.x, y: n.y, width: n.width, _id: n._id}}); // only thing we change is x,y,w and id to find it back
    this._layouts = this._layouts || []; // use array to find larger quick
    this._layouts[oldColumn] = copy;

    // if we're going to 1 column and using DOM order rather than default sorting, then generate that layout
    if (column === 1 && nodes && nodes.length) {
      var top = 0;
      nodes.forEach(function(n) {
        n.x = 0;
        n.width = 1;
        n.y = Math.max(n.y, top);
        top = n.y + n.height;
      });
    } else {
      nodes = Utils.sort(this.nodes, -1, oldColumn); // current column reverse sorting so we can insert last to front (limit collision)
    }

    // see if we have cached previous layout.
    var cacheNodes = this._layouts[column] || [];
    // if not AND we are going up in size start with the largest layout as down-scaling is more accurate
    var lastIndex = this._layouts.length - 1;
    if (cacheNodes.length === 0 && column > oldColumn && column < lastIndex) {
      cacheNodes = this._layouts[lastIndex] || [];
      if (cacheNodes.length) {
        // pretend we came from that larger column by assigning those values as starting point
        oldColumn = lastIndex;
        cacheNodes.forEach(function(cacheNode) {
          var j = nodes.findIndex(function(n) {return n && n._id === cacheNode._id});
          if (j !== -1) {
            // still current, use cache info positions
            nodes[j].x = cacheNode.x;
            nodes[j].y = cacheNode.y;
            nodes[j].width = cacheNode.width;
          }
        });
        cacheNodes = []; // we still don't have new column cached data... will generate from larger one.
      }
    }

    // if we found cache re-use those nodes that are still current
    var newNodes = [];
    cacheNodes.forEach(function(cacheNode) {
      var j = nodes.findIndex(function(n) {return n && n._id === cacheNode._id});
      if (j !== -1) {
        // still current, use cache info positions
        nodes[j].x = cacheNode.x;
        nodes[j].y = cacheNode.y;
        nodes[j].width = cacheNode.width;
        newNodes.push(nodes[j]);
        nodes[j] = null; // erase it so we know what's left
      }
    });
    // ...and add any extra non-cached ones
    var ratio = column / oldColumn;
    nodes.forEach(function(node) {
      if (!node) return;
      node.x = (column === 1 ? 0 : Math.round(node.x * ratio));
      node.width = ((column === 1 || oldColumn === 1) ? 1 : (Math.round(node.width * ratio) || 1));
      newNodes.push(node);
    });

    // finally relayout them in reverse order (to get correct placement)
    newNodes = Utils.sort(newNodes, -1, column);
    this._ignoreLayoutsNodeChange = true;
    this.batchUpdate();
    this.nodes = []; // pretend we have no nodes to start with (we use same structures) to simplify layout
    newNodes.forEach(function(node) {
      this.addNode(node, false); // 'false' for add event trigger
      node._dirty = true; // force attr update
    }, this);
    this.commit();
    delete this._ignoreLayoutsNodeChange;
  }

  /** called to save initial position/size */
  GridStackEngine.prototype._saveInitial = function() {
    this.nodes.forEach(function(n) {
      n._origX = n.x;
      n._origY = n.y;
      n._origW = n.width;
      n._origH = n.height;
      delete n._dirty;
    });
  }

  /**
   * Modify number of columns in the grid. Will attempt to update existing widgets
   * to conform to new number of columns. Requires `gridstack-extra.css` or `gridstack-extra.min.css` for [1-11],
   * else you will need to generate correct CSS (see https://github.com/gridstack/gridstack.js#change-grid-columns)
   * @param column - Integer > 0 (default 12).
   * @param doNotPropagate if true existing widgets will not be updated (optional)
   */
  GridStack.prototype.setColumn = function(column, doNotPropagate) {
    if (this.opts.column === column) { return; }
    var oldColumn = this.opts.column;

    // if we go into 1 column mode (which happens if we're sized less than minWidth unless disableOneColumnMode is on)
    // then remember the original columns so we can restore.
    if (column === 1) {
      this._prevColumn = oldColumn;
    } else {
      delete this._prevColumn;
    }

    this.container.removeClass('grid-stack-' + oldColumn);
    this.container.addClass('grid-stack-' + column);
    this.opts.column = this.grid.column = column;

    if (doNotPropagate === true) { return; }

    // update the items now - see if the dom order nodes should be passed instead (else default to current list)
    var domNodes;
    if (this.opts.oneColumnModeDomSort && column === 1) {
      domNodes = [];
      this.container.children('.' + this.opts.itemClass).each(function(index, el) {
        var node = $(el).data('_gridstack_node');
        if (node) { domNodes.push(node); }
      });
      if (!domNodes.length) { domNodes = undefined; }
    }
    this.grid._updateNodeWidths(oldColumn, column, domNodes);

    // and trigger our event last...
    this.grid._ignoreLayoutsNodeChange = true;
    this._triggerChangeEvent();
    delete this.grid._ignoreLayoutsNodeChange;
  };

  GridStack.prototype.float = function(val) {
    // getter - returns the opts stored mode
    if (val === undefined) {
      return this.opts.float || false;
    }
    // setter - updates the mode and relayout if gravity is back on
    if (this.opts.float === val) { return; }
    this.opts.float = this.grid.float = val || false;
    if (!val) {
      this.grid._packNodes();
      this.grid._notify();
      this._triggerChangeEvent();
    }
  };

  // legacy method renames
  GridStack.prototype.setGridWidth = obsolete(GridStack.prototype.setColumn,
    'setGridWidth', 'setColumn', 'v0.5.3');

  scope.GridStackUI = GridStack;

  scope.GridStackUI.Utils = Utils;
  scope.GridStackUI.Engine = GridStackEngine;
  scope.GridStackUI.GridStackDragDropPlugin = GridStackDragDropPlugin;

  $.fn.gridstack = function(opts) {
    return this.each(function() {
      var o = $(this);
      if (!o.data('gridstack')) {
        o
          .data('gridstack', new GridStack(this, opts));
      }
    });
  };

  return scope.GridStackUI;
});
/*! jQuery UI - v1.12.1 - 2019-11-20
* http://jqueryui.com
* Includes: widget.js, data.js, disable-selection.js, scroll-parent.js, widgets/draggable.js, widgets/droppable.js, widgets/resizable.js, widgets/mouse.js
* Copyright jQuery Foundation and other contributors; Licensed MIT @preserve*/

(function( factory ) {
  if ( typeof define === "function" && define.amd ) {

    // AMD. Register as an anonymous module.
    define([ "jquery" ], factory );
  } else {

    // Browser globals
    factory( jQuery );
  }
}(function( $ ) {

$.ui = $.ui || {};

var version = $.ui.version = "1.12.1";


/*!
 * jQuery UI Widget 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Widget
//>>group: Core
//>>description: Provides a factory for creating stateful widgets with a common API.
//>>docs: http://api.jqueryui.com/jQuery.widget/
//>>demos: http://jqueryui.com/widget/



var widgetUuid = 0;
var widgetSlice = Array.prototype.slice;

$.cleanData = ( function( orig ) {
  return function( elems ) {
    var events, elem, i;
    for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
      try {

        // Only trigger remove when necessary to save time
        events = $._data( elem, "events" );
        if ( events && events.remove ) {
          $( elem ).triggerHandler( "remove" );
        }

      // Http://bugs.jquery.com/ticket/8235
      } catch ( e ) {}
    }
    orig( elems );
  };
} )( $.cleanData );

$.widget = function( name, base, prototype ) {
  var existingConstructor, constructor, basePrototype;

  // ProxiedPrototype allows the provided prototype to remain unmodified
  // so that it can be used as a mixin for multiple widgets (#8876)
  var proxiedPrototype = {};

  var namespace = name.split( "." )[ 0 ];
  name = name.split( "." )[ 1 ];
  var fullName = namespace + "-" + name;

  if ( !prototype ) {
    prototype = base;
    base = $.Widget;
  }

  if ( $.isArray( prototype ) ) {
    prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
  }

  // Create selector for plugin
  $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
    return !!$.data( elem, fullName );
  };

  $[ namespace ] = $[ namespace ] || {};
  existingConstructor = $[ namespace ][ name ];
  constructor = $[ namespace ][ name ] = function( options, element ) {

    // Allow instantiation without "new" keyword
    if ( !this._createWidget ) {
      return new constructor( options, element );
    }

    // Allow instantiation without initializing for simple inheritance
    // must use "new" keyword (the code above always passes args)
    if ( arguments.length ) {
      this._createWidget( options, element );
    }
  };

  // Extend with the existing constructor to carry over any static properties
  $.extend( constructor, existingConstructor, {
    version: prototype.version,

    // Copy the object used to create the prototype in case we need to
    // redefine the widget later
    _proto: $.extend( {}, prototype ),

    // Track widgets that inherit from this widget in case this widget is
    // redefined after a widget inherits from it
    _childConstructors: []
  } );

  basePrototype = new base();

  // We need to make the options hash a property directly on the new instance
  // otherwise we'll modify the options hash on the prototype that we're
  // inheriting from
  basePrototype.options = $.widget.extend( {}, basePrototype.options );
  $.each( prototype, function( prop, value ) {
    if ( !$.isFunction( value ) ) {
      proxiedPrototype[ prop ] = value;
      return;
    }
    proxiedPrototype[ prop ] = ( function() {
      function _super() {
        return base.prototype[ prop ].apply( this, arguments );
      }

      function _superApply( args ) {
        return base.prototype[ prop ].apply( this, args );
      }

      return function() {
        var __super = this._super;
        var __superApply = this._superApply;
        var returnValue;

        this._super = _super;
        this._superApply = _superApply;

        returnValue = value.apply( this, arguments );

        this._super = __super;
        this._superApply = __superApply;

        return returnValue;
      };
    } )();
  } );
  constructor.prototype = $.widget.extend( basePrototype, {

    // TODO: remove support for widgetEventPrefix
    // always use the name + a colon as the prefix, e.g., draggable:start
    // don't prefix for widgets that aren't DOM-based
    widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
  }, proxiedPrototype, {
    constructor: constructor,
    namespace: namespace,
    widgetName: name,
    widgetFullName: fullName
  } );

  // If this widget is being redefined then we need to find all widgets that
  // are inheriting from it and redefine all of them so that they inherit from
  // the new version of this widget. We're essentially trying to replace one
  // level in the prototype chain.
  if ( existingConstructor ) {
    $.each( existingConstructor._childConstructors, function( i, child ) {
      var childPrototype = child.prototype;

      // Redefine the child widget using the same prototype that was
      // originally used, but inherit from the new version of the base
      $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
        child._proto );
    } );

    // Remove the list of existing child constructors from the old constructor
    // so the old child constructors can be garbage collected
    delete existingConstructor._childConstructors;
  } else {
    base._childConstructors.push( constructor );
  }

  $.widget.bridge( name, constructor );

  return constructor;
};

$.widget.extend = function( target ) {
  var input = widgetSlice.call( arguments, 1 );
  var inputIndex = 0;
  var inputLength = input.length;
  var key;
  var value;

  for ( ; inputIndex < inputLength; inputIndex++ ) {
    for ( key in input[ inputIndex ] ) {
      value = input[ inputIndex ][ key ];
      if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {

        // Clone objects
        if ( $.isPlainObject( value ) ) {
          target[ key ] = $.isPlainObject( target[ key ] ) ?
            $.widget.extend( {}, target[ key ], value ) :

            // Don't extend strings, arrays, etc. with objects
            $.widget.extend( {}, value );

        // Copy everything else by reference
        } else {
          target[ key ] = value;
        }
      }
    }
  }
  return target;
};

$.widget.bridge = function( name, object ) {
  var fullName = object.prototype.widgetFullName || name;
  $.fn[ name ] = function( options ) {
    var isMethodCall = typeof options === "string";
    var args = widgetSlice.call( arguments, 1 );
    var returnValue = this;

    if ( isMethodCall ) {

      // If this is an empty collection, we need to have the instance method
      // return undefined instead of the jQuery instance
      if ( !this.length && options === "instance" ) {
        returnValue = undefined;
      } else {
        this.each( function() {
          var methodValue;
          var instance = $.data( this, fullName );

          if ( options === "instance" ) {
            returnValue = instance;
            return false;
          }

          if ( !instance ) {
            return $.error( "cannot call methods on " + name +
              " prior to initialization; " +
              "attempted to call method '" + options + "'" );
          }

          if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
            return $.error( "no such method '" + options + "' for " + name +
              " widget instance" );
          }

          methodValue = instance[ options ].apply( instance, args );

          if ( methodValue !== instance && methodValue !== undefined ) {
            returnValue = methodValue && methodValue.jquery ?
              returnValue.pushStack( methodValue.get() ) :
              methodValue;
            return false;
          }
        } );
      }
    } else {

      // Allow multiple hashes to be passed on init
      if ( args.length ) {
        options = $.widget.extend.apply( null, [ options ].concat( args ) );
      }

      this.each( function() {
        var instance = $.data( this, fullName );
        if ( instance ) {
          instance.option( options || {} );
          if ( instance._init ) {
            instance._init();
          }
        } else {
          $.data( this, fullName, new object( options, this ) );
        }
      } );
    }

    return returnValue;
  };
};

$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];

$.Widget.prototype = {
  widgetName: "widget",
  widgetEventPrefix: "",
  defaultElement: "<div>",

  options: {
    classes: {},
    disabled: false,

    // Callbacks
    create: null
  },

  _createWidget: function( options, element ) {
    element = $( element || this.defaultElement || this )[ 0 ];
    this.element = $( element );
    this.uuid = widgetUuid++;
    this.eventNamespace = "." + this.widgetName + this.uuid;

    this.bindings = $();
    this.hoverable = $();
    this.focusable = $();
    this.classesElementLookup = {};

    if ( element !== this ) {
      $.data( element, this.widgetFullName, this );
      this._on( true, this.element, {
        remove: function( event ) {
          if ( event.target === element ) {
            this.destroy();
          }
        }
      } );
      this.document = $( element.style ?

        // Element within the document
        element.ownerDocument :

        // Element is window or document
        element.document || element );
      this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
    }

    this.options = $.widget.extend( {},
      this.options,
      this._getCreateOptions(),
      options );

    this._create();

    if ( this.options.disabled ) {
      this._setOptionDisabled( this.options.disabled );
    }

    this._trigger( "create", null, this._getCreateEventData() );
    this._init();
  },

  _getCreateOptions: function() {
    return {};
  },

  _getCreateEventData: $.noop,

  _create: $.noop,

  _init: $.noop,

  destroy: function() {
    var that = this;

    this._destroy();
    $.each( this.classesElementLookup, function( key, value ) {
      that._removeClass( value, key );
    } );

    // We can probably remove the unbind calls in 2.0
    // all event bindings should go through this._on()
    this.element
      .off( this.eventNamespace )
      .removeData( this.widgetFullName );
    this.widget()
      .off( this.eventNamespace )
      .removeAttr( "aria-disabled" );

    // Clean up events and states
    this.bindings.off( this.eventNamespace );
  },

  _destroy: $.noop,

  widget: function() {
    return this.element;
  },

  option: function( key, value ) {
    var options = key;
    var parts;
    var curOption;
    var i;

    if ( arguments.length === 0 ) {

      // Don't return a reference to the internal hash
      return $.widget.extend( {}, this.options );
    }

    if ( typeof key === "string" ) {

      // Handle nested keys, e.g., "foo.bar" = { foo: { bar: ___ } }
      options = {};
      parts = key.split( "." );
      key = parts.shift();
      if ( parts.length ) {
        curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
        for ( i = 0; i < parts.length - 1; i++ ) {
          curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
          curOption = curOption[ parts[ i ] ];
        }
        key = parts.pop();
        if ( arguments.length === 1 ) {
          return curOption[ key ] === undefined ? null : curOption[ key ];
        }
        curOption[ key ] = value;
      } else {
        if ( arguments.length === 1 ) {
          return this.options[ key ] === undefined ? null : this.options[ key ];
        }
        options[ key ] = value;
      }
    }

    this._setOptions( options );

    return this;
  },

  _setOptions: function( options ) {
    var key;

    for ( key in options ) {
      this._setOption( key, options[ key ] );
    }

    return this;
  },

  _setOption: function( key, value ) {
    if ( key === "classes" ) {
      this._setOptionClasses( value );
    }

    this.options[ key ] = value;

    if ( key === "disabled" ) {
      this._setOptionDisabled( value );
    }

    return this;
  },

  _setOptionClasses: function( value ) {
    var classKey, elements, currentElements;

    for ( classKey in value ) {
      currentElements = this.classesElementLookup[ classKey ];
      if ( value[ classKey ] === this.options.classes[ classKey ] ||
          !currentElements ||
          !currentElements.length ) {
        continue;
      }

      // We are doing this to create a new jQuery object because the _removeClass() call
      // on the next line is going to destroy the reference to the current elements being
      // tracked. We need to save a copy of this collection so that we can add the new classes
      // below.
      elements = $( currentElements.get() );
      this._removeClass( currentElements, classKey );

      // We don't use _addClass() here, because that uses this.options.classes
      // for generating the string of classes. We want to use the value passed in from
      // _setOption(), this is the new value of the classes option which was passed to
      // _setOption(). We pass this value directly to _classes().
      elements.addClass( this._classes( {
        element: elements,
        keys: classKey,
        classes: value,
        add: true
      } ) );
    }
  },

  _setOptionDisabled: function( value ) {
    this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );

    // If the widget is becoming disabled, then nothing is interactive
    if ( value ) {
      this._removeClass( this.hoverable, null, "ui-state-hover" );
      this._removeClass( this.focusable, null, "ui-state-focus" );
    }
  },

  enable: function() {
    return this._setOptions( { disabled: false } );
  },

  disable: function() {
    return this._setOptions( { disabled: true } );
  },

  _classes: function( options ) {
    var full = [];
    var that = this;

    options = $.extend( {
      element: this.element,
      classes: this.options.classes || {}
    }, options );

    function processClassString( classes, checkOption ) {
      var current, i;
      for ( i = 0; i < classes.length; i++ ) {
        current = that.classesElementLookup[ classes[ i ] ] || $();
        if ( options.add ) {
          current = $( $.unique( current.get().concat( options.element.get() ) ) );
        } else {
          current = $( current.not( options.element ).get() );
        }
        that.classesElementLookup[ classes[ i ] ] = current;
        full.push( classes[ i ] );
        if ( checkOption && options.classes[ classes[ i ] ] ) {
          full.push( options.classes[ classes[ i ] ] );
        }
      }
    }

    this._on( options.element, {
      "remove": "_untrackClassesElement"
    } );

    if ( options.keys ) {
      processClassString( options.keys.match( /\S+/g ) || [], true );
    }
    if ( options.extra ) {
      processClassString( options.extra.match( /\S+/g ) || [] );
    }

    return full.join( " " );
  },

  _untrackClassesElement: function( event ) {
    var that = this;
    $.each( that.classesElementLookup, function( key, value ) {
      if ( $.inArray( event.target, value ) !== -1 ) {
        that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
      }
    } );
  },

  _removeClass: function( element, keys, extra ) {
    return this._toggleClass( element, keys, extra, false );
  },

  _addClass: function( element, keys, extra ) {
    return this._toggleClass( element, keys, extra, true );
  },

  _toggleClass: function( element, keys, extra, add ) {
    add = ( typeof add === "boolean" ) ? add : extra;
    var shift = ( typeof element === "string" || element === null ),
      options = {
        extra: shift ? keys : extra,
        keys: shift ? element : keys,
        element: shift ? this.element : element,
        add: add
      };
    options.element.toggleClass( this._classes( options ), add );
    return this;
  },

  _on: function( suppressDisabledChecknt, handlers ) {
    var delegateElement;
    var instance = this;

    // No suppressDisabledCheck flag, shuffle arguments
    if ( typeof suppressDisabledCheck !== "boolean" ) {
      handlers = element;
      element = suppressDisabledCheck;
      suppressDisabledCheck = false;
    }

    // No element argument, shuffle and use this.element
    if ( !handlers ) {
      handlers = element;
      element = this.element;
      delegateElement = this.widget();
    } else {
      element = delegateElement = $( element );
      this.bindings = this.bindings.add( element );
    }

    $.each( handlers, function( event, handler ) {
      function handlerProxy() {

        // Allow widgets to customize the disabled handling
        // - disabled as an array instead of boolean
        // - disabled class as method for disabling individual parts
        if ( !suppressDisabledCheck &&
            ( instance.options.disabled === true ||
            $( this ).hasClass( "ui-state-disabled" ) ) ) {
          return;
        }
        return ( typeof handler === "string" ? instance[ handler ] : handler )
          .apply( instance, arguments );
      }

      // Copy the guid so direct unbinding works
      if ( typeof handler !== "string" ) {
        handlerProxy.guid = handler.guid =
          handler.guid || handlerProxy.guid || $.guid++;
      }

      var match = event.match( /^([\w:-]*)\s*(.*)$/ );
      var eventName = match[ 1 ] + instance.eventNamespace;
      var selector = match[ 2 ];

      if ( selector ) {
        delegateElement.on( eventName, selector, handlerProxy );
      } else {
        element.on( eventName, handlerProxy );
      }
    } );
  },

  _off: function( element, eventName ) {
    eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
      this.eventNamespace;
    element.off( eventName ).off( eventName );

    // Clear the stack to avoid memory leaks (#10056)
    this.bindings = $( this.bindings.not( element ).get() );
    this.focusable = $( this.focusable.not( element ).get() );
    this.hoverable = $( this.hoverable.not( element ).get() );
  },

  _delay: function( handler, delay ) {
    function handlerProxy() {
      return ( typeof handler === "string" ? instance[ handler ] : handler )
        .apply( instance, arguments );
    }
    var instance = this;
    return setTimeout( handlerProxy, delay || 0 );
  },

  _hoverable: function( element ) {
    this.hoverable = this.hoverable.add( element );
    this._on( element, {
      mouseenter: function( event ) {
        this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
      },
      mouseleave: function( event ) {
        this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
      }
    } );
  },

  _focusable: function( element ) {
    this.focusable = this.focusable.add( element );
    this._on( element, {
      focusin: function( event ) {
        this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
      },
      focusout: function( event ) {
        this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
      }
    } );
  },

  _trigger: function( type, event, data ) {
    var prop, orig;
    var callback = this.options[ type ];

    data = data || {};
    event = $.Event( event );
    event.type = ( type === this.widgetEventPrefix ?
      type :
      this.widgetEventPrefix + type ).toLowerCase();

    // The original event may come from any element
    // so we need to reset the target on the new event
    event.target = this.element[ 0 ];

    // Copy original event properties over to the new event
    orig = event.originalEvent;
    if ( orig ) {
      for ( prop in orig ) {
        if ( !( prop in event ) ) {
          event[ prop ] = orig[ prop ];
        }
      }
    }

    this.element.trigger( event, data );
    return !( $.isFunction( callback ) &&
      callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
      event.isDefaultPrevented() );
  }
};

$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEff) {
  $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
    if ( typeof options === "string" ) {
      options = { effect: options };
    }

    var hasOptions;
    var effectName = !options ?
      method :
      options === true || typeof options === "number" ?
        defaultEffect :
        options.effect || defaultEffect;

    options = options || {};
    if ( typeof options === "number" ) {
      options = { duration: options };
    }

    hasOptions = !$.isEmptyObject( options );
    options.complete = callback;

    if ( options.delay ) {
      element.delay( options.delay );
    }

    if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
      element[ method ]( options );
    } else if ( effectName !== method && element[ effectName ] ) {
      element[ effectName ]( options.duration, options.easing, callback );
    } else {
      element.queue( function( next ) {
        $( this )[ method ]();
        if ( callback ) {
          callback.call( element[ 0 ] );
        }
        next();
      } );
    }
  };
} );

var widget = $.widget;


/*!
 * jQuery UI :data 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: :data Selector
//>>group: Core
//>>description: Selects elements which have data stored under the specified key.
//>>docs: http://api.jqueryui.com/data-selector/


var data = $.extend( $.expr[ ":" ], {
  data: $.expr.createPseudo ?
    $.expr.createPseudo( function( dataName ) {
      return function( elem ) {
        return !!$.data( elem, dataName );
      };
    } ) :

    // Support: jQuery <1.8
    function( elem, i, match ) {
      return !!$.data( elem, match[ 3 ] );
    }
} );

/*!
 * jQuery UI Disable Selection 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: disableSelection
//>>group: Core
//>>description: Disable selection of text content within the set of matched elements.
//>>docs: http://api.jqueryui.com/disableSelection/

// This file is deprecated


var disableSelection = $.fn.extend( {
  disableSelection: ( function() {
    var eventType = "onselectstart" in document.createElement( "div" ) ?
      "selectstart" :
      "mousedown";

    return function() {
      return this.on( eventType + ".ui-disableSelection", function( event ) {
        event.preventDefault();
      } );
    };
  } )(),

  enableSelection: function() {
    return this.off( ".ui-disableSelection" );
  }
} );


/*!
 * jQuery UI Scroll Parent 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: scrollParent
//>>group: Core
//>>description: Get the closest ancestor element that is scrollable.
//>>docs: http://api.jqueryui.com/scrollParent/



var scrollParent = $.fn.scrollParent = function( includeHidden ) {
  var position = this.css( "position" ),
    excludeStaticParent = position === "absolute",
    overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
    scrollParent = this.parents().filter( function() {
      var parent = $( this );
      if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
        return false;
      }
      return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
        parent.css( "overflow-x" ) );
    } ).eq( 0 );

  return position === "fixed" || !scrollParent.length ?
    $( this[ 0 ].ownerDocument || document ) :
    scrollParent;
};




// This file is deprecated
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );

/*!
 * jQuery UI Mouse 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Mouse
//>>group: Widgets
//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
//>>ds: http://api.jqueryui.com/mouse/



var mouseHandled = false;
$( document ).on( "mouseup", function() {
  mouseHandled = false;
} );

var widgetsMouse = $.widget( "ui.mouse", {
  version: "1.12.1",
  options: {
    cancel: "input, textarea, button, select, option",
    distance: 1,
    delay: 0
  },
  _mouseInit: function() {
    var that = this;

    this.element
      .on( "mousedown." + this.widgetName, function( event ) {
        return that._mouseDown( event );
      } )
      .on( "click." + this.widgetName, function( event ) {
        if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
          $.removeData( event.target, that.widgetName + ".preventClickEvent" );
          event.stopImmediatePropagation();
          return false;
        }
      } );

    this.started = false;
  },

  // TODO: make sure destroying one instance of mouse doesn't mess with
  // other instances of mouse
  _mouseDestroy: function() {
    this.element.off( "." + this.widgetName );
    if ( this._mouseMoveDelegate ) {
      this.document
        .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
        .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
    }
  },

  _mouseDown: function( event ) {

    // don't let more than one widget handle mouseStart
    if ( mouseHandled ) {
      return;
    }

    this._mouseMoved = false;

    // We may have missed mouseup (out of window)
    ( this._mouseStarted && this._mouseUp( event ) );

    this._mouseDownEvent = event;

    var that = this,
      btnIsLeft = ( event.which === 1 ),

      // event.target.nodeName works around a bug in IE 8 with
      // disabled inputs (#7620)
      elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
        $( event.target ).closest( this.options.cancel ).length : false );
    if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
      return true;
    }

    this.mouseDelayMet = !this.options.delay;
    if ( !this.mouseDelayMet ) {
      this._mouseDelayTimer = setTimeout( function() {
        that.mouseDelayMet = true;
      }, this.options.delay );
    }

    if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
      this._mouseStarted = ( this._mouseStart( event ) !== false );
      if ( !this._mouseStarted ) {
        event.preventDefault();
        return true;
      }
    }

    // Click event may never have fired (Gecko & Opera)
    if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
      $.removeData( event.target, this.widgetName + ".preventClickEvent" );
    }

    // These delegates are required to keep context
    this._mouseMoveDelegate = function( event ) {
      return that._mouseMove( event );
    };
    this._mouseUpDelegate = function( event ) {
      return that._mouseUp( event );
    };

    this.document
      .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
      .on( "mouseup." + this.widgetName, this._mouseUpDelegate );

    event.preventDefault();

    mouseHandled = true;
    return true;
  },

  _mouseMove: function( event ) {

    // Only check for mouseups outside the document if you've moved inside the document
    // at least once. This prevents the firing of mouseup in the case of IE<9, which will
    // fire a mousemove event if content is placed under the cursor. See #7778
    // Support: IE <9
    if ( this._mouseMoved ) {

      // IE mouseup check - mouseup happened when mouse was out of window
      if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
          !event.button ) {
        return this._mouseUp( event );

      // Iframe mouseup check - mouseup occurred in another document
      } else if ( !event.which ) {

        // Support: Safari <=8 - 9
        // Safari sets which to 0 if you press any of the following keys
        // during a drag (#14461)
        if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
            event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
          this.ignoreMissingWhic;
        } else if ( !this.ignoreMissingWhich ) {
          return this._mouseUp( event );
        }
      }
    }

    if ( event.which || event.button ) {
      this._mouseMoved = true;
    }

    if ( this._mouseStarted ) {
      this._mouseDrag( event );
      return event.preventDefault();
    }

    if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
      this._mouseStarted =
        ( this._mouseStart( this._mouseDownEvent, event ) !== false );
      ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
    }

    return !this._mouseStarted;
  },

  _mouseUp: function( event ) {
    this.document
      .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
      .off( "mouseup." + this.widgetName, this._mouseUpDelegate );

    if ( this._mouseStarted ) {
      this._mouseStarted = false;

      if ( event.target === this._mouseDownEvent.target ) {
        $.data( event.target, this.widgetName + ".preventClickEvent", true );
      }

      this._mouseStop( event );
    }

    if ( this._mouseDelayTimer ) {
      clearTimeout( this._mouseDelayTimer );
      delete this._mouseDelayTimer;
    }

    this.ignoreMissingWhich = false;
    mouseHandled = false;
    event.preventDefault();
  },

  _mouseDistanceMet: function( event ) {
    return ( Math.max(
        Math.abs( this._mouseDownEvent.pageX - event.pageX ),
        Math.abs( this._mouseDownEvent.pageY - event.pageY )
      ) >= this.options.distance
    );
  },

  _mouseDelayMet: function( /* event */ ) {
    return this.mouseDelayMet;
  },

  // These are placeholder methods, to be overriden by extending plugin
  _mouseStart: function( /* event */ ) {},
  _mouseDrag: function( /* event */ ) {},
  _mouseStop: function( /* event */ ) {},
  _mouseCapture: function( /* event */ ) { return true; }
} );




// $.ui.plugin is deprecated. Use $.widget() extensions instead.
var plugin = $.ui.plugin = {
  add: function( module, option, set ) {
    var i,
      proto = $.ui[ module ].prototype;
    for ( i in set ) {
      proto.plugins[ i ] = proto.plugins[ i ] || [];
      proto.plugins[ i ].push( [ option, set[ i ] ] );
    }
  },
  call: function( instance, name, args, allowDisconnected ) {
    var i,
      set = instance.plugins[ name ];

    if ( !set ) {
      return;
    }

    if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
        instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
      return;
    }

    for ( i = 0; i < set.length; i++ ) {
      if ( instance.options[ set[ i ][ 0 ] ] ) {
        set[ i ][ 1 ].apply( instance.element, args );
      }
    }
  }
};



var safeActiveElement = $.ui.safeActiveElement = function( document ) {
  var activeElement;

  // Support: IE 9 only
  // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
  try {
    activeElement = document.activeElement;
  } catch ( error ) {
    activeElement = document.body;
  }

  // Support: IE 9 - 11 only
  // IE may return null instead of an element
  // Interestingly, this only seems to occur when NOT in an iframe
  if ( !activeElement ) {
    activeElement = document.body;
  }

  // Support: IE 11 only
  // IE11 returns a seemingly empty object in some cases when accessing
  // document.activeElement from an <iframe>
  if ( !activeElement.nodeName ) {
    activeElement = document.body;
  }

  return activeElement;
};



var safeBlur = $.ui.safeBlur = function( element ) {

  // Support: IE9 - 10 only
  // If the <body> is blurred, IE will switch windows, see #9420
  if ( element && element.nodeName.toLowerCase() !== "body" ) {
    $( element ).trigger( "blur" );
  }
};


/*!
 * jQuery UI Draggable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Draggable
//>>group: Interactions
//>>description: Enables dragging functionality for any element.
//>>docs: http://api.jqueryui.com/draggable/
//>>demos: http://jqueryui.com/draggable/
//>>css.structure: ../../themes/base/draggable.css



$.widget( "ui.draggable", $.ui.mouse, {
  version: "1.12.1",
  widgetEventPrefix: "drag",
  options: {
    addClasses: true,
    appendTo: "parent",
    axis: false,
    connectToSortable: false,
    containment: false,
    cursor: "auto",
    cursorAt: false,
    grid: false,
    handle: false,
    helper: "original",
    iframeFix: false,
    opacity: false,
    refreshPositions: false,
    revert: false,
    revertDuration: 500,
    scope: "default",
    scroll: true,
    scrollSensitivity: 20,
    scrollSpeed: 20,
    snap: false,
    snapMode: "both",
    snapTolerance: 20,
    stack: false,
    zIndex: false,

    // Callbacks
    drag: null,
    start: null,
    stop: null
  },
  _create: function() {

    if ( this.options.helper === "original" ) {
      this._setPositionRelative();
    }
    if ( this.options.addClasses ) {
      this._addClass( "ui-draggable" );
    }
    this._setHandleClassName();

    this._mouseInit();
  },

  _setOption: function( key, value ) {
    this._super( key, value );
    if ( key === "handle" ) {
      this._removeHandleClassName();
      this._setHandleClassName();
    }
  },

  _destroy: function() {
    if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
      this.destroyOnClear = true;
      return;
    }
    this._removeHandleClassName();
    this._mouseDestroy();
  },

  _mouseCapture: function( event ) {
    var o = this.options;

    // Among others, prevent a drag on a resizable-handle
    if ( this.helper || o.disabled ||
        $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
      return false;
    }

    //Quit if we're not on a valid handle
    this.handle = this._getHandle( event );
    if ( !this.handle ) {
      return false;
    }

    this._blurActiveElement( event );

    this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );

    return true;

  },

  _blockFrames: function( selector ) {
    this.iframeBlocks = this.document.find( selector ).map( function() {
      var iframe = $( this );

      return $( "<div>" )
        .css( "position", "absolute" )
        .appendTo( iframe.parent() )
        .outerWidth( iframe.outerWidth() )
        .outerHeight( iframe.outerHeight() )
        .offset( iframe.offset() )[ 0 ];
    } );
  },

  _unblockFrames: function() {
    if ( this.iframeBlocks ) {
      this.iframeBlocks.remove();
      delete this.iframeBlocks;
    }
  },

  _blurActiveElement: function( event ) {
    var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
      target = $( event.target );

    // Don't blur if the event occurred on an element that is within
    // the currently focused element
    // See #10527, #12472
    if ( target.closest( activeElement ).length ) {
      return;
    }

    // Blur any element that currently has focus, see #4261
    $.ui.safeBlur( activeElement );
  },

  _mouseStart: function( event ) {

    var o = this.options;

    //Create and append the visible helper
    this.helper = this._createHelper( event );

    this._addClass( this.helper, "ui-draggable-dragging" );

    //Cache the helper size
    this._cacheHelperProportions();

    //If ddmanager is used for droppables, set the global draggable
    if ( $.ui.ddmanager ) {
      $.ui.ddmanager.current = this;
    }

    /*
     * - Position generation -
     * This block generates everything position related - it's the core of draggables.
     */

    //Cache the margins of the original element
    this._cacheMargins();

    //Store the helper's css position
    this.cssPosition = this.helper.css( "position" );
    this.scrollParent = this.helper.scrollParent( true );
    this.offsetParent = this.helper.offsetParent();
    this.hasFixedAncestor = this.helper.parents().filter( function() {
        return $( this ).css( "position" ) === "fixed";
      } ).length > 0;

    //The element's absolute position on the page minus margins
    this.positionAbs = this.element.offset();
    this._refreshOffsets( event );

    //Generate the original position
    this.originalPosition = this.position = this._generatePosition( event, false );
    this.originalPageX = event.pageX;
    this.originalPageY = event.pageY;

    //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
    ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );

    //Set a containment if given in the options
    this._setContainment();

    //Trigger event + callbacks
    if ( this._trigger( "start", event ) === false ) {
      this._clear();
      return false;
    }

    //Recache the helper size
    this._cacheHelperProportions();

    //Prepare the droppable offsets
    if ( $.ui.ddmanager && !o.dropBehaviour ) {
      $.ui.ddmanager.prepareOffsets( this, event );
    }

    // Execute the drag once - this causes the helper not to be visible before getting its
    // correct position
    this._mouseDrag( event, true );

    // If the ddmanager is used for droppables, inform the manager that dragging has started
    // (see #5003)
    if ( $.ui.ddmanager ) {
      $.ui.ddmanager.dragStart( this, event );
    }

    return true;
  },

  _refreshOffsets: function( event ) {
    this.offset = {
      top: this.positionAbs.top - this.margins.top,
      left: this.positionAbs.left - this.margins.left,
      scroll: false,
      parent: this._getParentOffset(),
      relative: this._getRelativeOffset()
    };

    this.offset.click = {
      left: event.pageX - this.offset.left,
      top: event.pageY - this.offset.top
    };
  },

  _mouseDrag: function( event, noPropagation ) {

    // reset any necessary cached properties (see #5009)
    if ( this.hasFixedAncestor ) {
      this.offset.parent = this._getParentOffset();
    }

    //Compute the helpers position
    this.position = this._generatePosition( event, true );
    this.positionAbs = this._convertPositionTo( "absolute" );

    //Call plugins and callbacks and use the resulting position if something is returned
    if ( !noPropagation ) {
      var ui = this._uiHash();
      if ( this._trigger( "drag", event, ui ) === false ) {
        this._mouseUp( new $.Event( "mouseup", event ) );
        return false;
      }
      this.position = ui.position;
    }

    this.helper[ 0 ].style.left = this.position.left + "px";
    this.helper[ 0 ].style.top = this.position.top + "px";

    if ( $.ui.ddmanager ) {
      $.ui.ddmanager.drag( this, event );
    }

    return false;
  },

  _mouseStop: function( event ) {

    //If we are using droppables, inform the manager about the drop
    var that = this,
      dropped = false;
    if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
      dropped = $.ui.ddmanager.drop( this, event );
    }

    //if a drop comes from outside (a sortable)
    if ( this.dropped ) {
      dropped = this.dropped;
      this.dropped = false;
    }

    if ( ( this.options.revert === "invalid" && !dropped ) ||
        ( this.options.revert === "valid" && dropped ) ||
        this.options.revert === true || ( $.isFunction( this.options.revert ) &&
        this.options.revert.call( this.element, dropped ) )
    ) {
      $( this.helper ).animate(
        this.originalPosition,
        parseInt( this.options.revertDuration, 10 ),
        function() {
          if ( that._trigger( "stop", event ) !== false ) {
            that._clear();
          }
        }
      );
    } else {
      if ( this._trigger( "stop", event ) !== false ) {
        this._clear();
      }
    }

    return false;
  },

  _mouseUp: function( event ) {
    this._unblockFrames();

    // If the ddmanager is used for droppables, inform the manager that dragging has stopped
    // (see #5003)
    if ( $.ui.ddmanager ) {
      $.ui.ddmanager.dragStop( this, event );
    }

    // Only need to focus if the event occurred on the draggable itself, see #10527
    if ( this.handleElement.is( event.target ) ) {

      // The interaction is over; whether or not the click resulted in a drag,
      // focus the element
      this.element.trigger( "focus" );
    }

    return $.ui.mouse.prototype._mouseUp.call( this, event );
  },

  cancel: function() {

    if ( this.helper.is( ".ui-draggable-dragging" ) ) {
      this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
    } else {
      this._clear();
    }

    return this;

  },

  _getHandle: function( event ) {
    return this.options.handle ?
      !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
      true;
  },

  _setHandleClassName: function() {
    this.handleElement = this.options.handle ?
      this.element.find( this.options.handle ) : this.element;
    this._addClass( this.handleElement, "ui-draggable-handle" );
  },

  _removeHandleClassName: function() {
    this._removeClass( this.handleElement, "ui-draggable-handle" );
  },

  _createHelper: function( event ) {

    var o = this.options,
      helperIsFunction = $.isFunction( o.helper ),
      helper = helperIsFunction ?
        $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
        ( o.helper === "clone" ?
          this.element.clone().removeAttr( "id" ) :
          this.element );

    if ( !helper.parents( "body" ).length ) {
      helper.appendTo( ( o.appendTo === "parent" ?
        this.element[ 0 ].parentNode :
        o.appendTo ) );
    }

    // Http://bugs.jqueryui.com/ticket/9446
    // a helper function can return the original element
    // which wouldn't have been set to relative in _create
    if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
      this._setPositionRelative();
    }

    if ( helper[ 0 ] !== this.element[ 0 ] &&
        !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
      helper.css( "position", "absolute" );
    }

    return helper;

  },

  _setPositionRelative: function() {
    if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
      this.element[ 0 ].style.position = "relative";
    }
  },

  _adjustOffsetFromHelper: function( obj ) {
    if ( typeof obj === "string" ) {
      obj = obj.split( " " );
    }
    if ( $.isArray( obj ) ) {
      obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
    }
    if ( "left" in obj ) {
      this.offset.click.left = obj.left + this.margins.left;
    }
    if ( "right" in obj ) {
      this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
    }
    if ( "top" in obj ) {
      this.offset.click.top = obj.top + this.margins.top;
    }
    if ( "bottom" in obj ) {
      this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
    }
  },

  _isRootNode: function( element ) {
    return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
  },

  _getParentOffset: function() {

    //Get the offsetParent and cache its position
    var po = this.offsetParent.offset(),
      document = this.document[ 0 ];

    // This is a special case where we need to modify a offset calculated on start, since the
    // following happened:
    // 1. The position of the helper is absolute, so it's position is calculated based on the
    // next positioned parent
    // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
    // the document, which means that the scroll is included in the initial calculation of the
    // offset of the parent, and never recalculated upon drag
    if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
        $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
      po.left += this.scrollParent.scrollLeft();
      po.top += this.scrollParent.scrollTop();
    }

    if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
      po = { top: 0, left: 0 };
    }

    return {
      top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
      left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
    };

  },

  _getRelativeOffset: function() {
    if ( this.cssPosition !== "relative" ) {
      return { top: 0, left: 0 };
    }

    var p = this.element.position(),
      scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );

    return {
      top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
        ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
      left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
        ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
    };

  },

  _cacheMargins: function() {
    this.margins = {
      left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
      top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
      right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
      bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
    };
  },

  _cacheHelperProportions: function() {
    this.helperProportions = {
      width: this.helper.outerWidth(),
      height: this.helper.outerHeight()
    };
  },

  _setContainment: function() {

    var isUserScrollable, c, ce,
      o = this.options,
      document = this.document[ 0 ];

    this.relativeContainer = null;

    if ( !o.containment ) {
      this.containment = null;
      return;
    }

    if ( o.containment === "window" ) {
      this.containment = [
        $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
        $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
        $( window ).scrollLeft() + $( window ).width() -
          this.helperProportions.width - this.margins.left,
        $( window ).scrollTop() +
          ( $( window ).height() || document.body.parentNode.scrollHeight ) -
          this.helperProportions.height - this.margins.top
      ];
      return;
    }

    if ( o.containment === "document" ) {
      this.containment = [
        0,
        0,
        $( document ).width() - this.helperProportions.width - this.margins.left,
        ( $( document ).height() || document.body.parentNode.scrollHeight ) -
          this.helperProportions.height - this.margins.top
      ];
      return;
    }

    if ( o.containment.constructor === Array ) {
      this.containment = o.containment;
      return;
    }

    if ( o.containment === "parent" ) {
      o.containment = this.helper[ 0 ].parentNode;
    }

    c = $( o.containment );
    ce = c[ 0 ];

    if ( !ce ) {
      return;
    }

    isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );

    this.containment = [
      ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
        ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
      ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
        ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
      ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
        ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
        ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
        this.helperProportions.width -
        this.margins.left -
        this.margins.right,
      ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
        ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
        ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
        this.helperProportions.height -
        this.margins.top -
        this.margins.bottom
    ];
    this.relativeContainer = c;
  },

  _convertPositionTo: function( d, pos ) {

    if ( !pos ) {
      pos = this.position;
    }

    var mod = d === "absolute" ? 1 : -1,
      scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );

    return {
      top: (

        // The absolute mouse position
        pos.top	+

        // Only for relative positioned nodes: Relative offset from element to offset parent
        this.offset.relative.top * mod +

        // The offsetParent's offset without borders (offset + border)
        this.offset.parent.top * mod -
        ( ( this.cssPosition === "fixed" ?
          -this.offset.scroll.top :
          ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
      ),
      left: (

        // The absolute mouse position
        pos.left +

        // Only for relative positioned nodes: Relative offset from element to offset parent
        this.offset.relativ* mod +

        // The offsetParent's offset without borders (offset + border)
        this.offset.parent.left * mod	-
        ( ( this.cssPosition === "fixed" ?
          -this.offset.scroll.left :
          ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
      )
    };

  },

  _generatePosition: function( event, constrainPosition ) {

    var containment, co, top, left,
      o = this.options,
      scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
      pageX = event.pageX,
      pageY = event.pageY;

    // Cache the scroll
    if ( !scrollIsRootNode || !this.offset.scroll ) {
      this.offset.scroll = {
        top: this.scrollParent.scrollTop(),
        left: this.scrollParent.scrollLeft()
      };
    }

    /*
     * - Position constraining -
     * Constrain the position to a mix of grid, containment.
     */

    // If we are not dragging yet, we won't check for options
    if ( constrainPosition ) {
      if ( this.containment ) {
        if ( this.relativeContainer ) {
          co = this.relativeContainer.offset();
          containment = [
            this.containment[ 0 ] + co.left,
            this.containment[ 1 ] + co.top,
            this.containment[ 2 ] + co.left,
            this.containment[ 3 ] + co.top
          ];
        } else {
          containment = this.containment;
        }

        if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
          pageX = containment[ 0 ] + this.offset.click.left;
        }
        if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
          pageY = containment[ 1 ] + this.offset.click.top;
        }
        if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
          pageX = containment[ 2 ] + this.offset.click.left;
        }
        if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
          pageY = containment[ 3 ] + this.offset.click.top;
        }
      }

      if ( o.grid ) {

        //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
        // argument errors in IE (see ticket #6950)
        top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
          this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
        pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
          top - this.offset.click.top > containment[ 3 ] ) ?
            top :
            ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
              top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;

        left = o.grid[ 0 ] ? this.originalPageX +
          Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
          this.originalPageX;
        pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
          left - this.offset.click.left > containment[ 2 ] ) ?
            left :
            ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
              left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
      }

      if ( o.axis === "y" ) {
        pageX = this.originalPageX;
      }

      if ( o.axis === "x" ) {
        pageY = this.originalPageY;
      }
    }

    return {
      top: (

        // The absolute mouse position
        pageY -

        // Click offset (relative to the element)
        this.offset.click.top -

        // Only for relative positioned nodes: Relative offset from element to offset parent
        this.offset.relative.top -

        // The offsetParent's offset without borders (offset + border)
        this.offset.parent.top +
        ( this.cssPosition === "fixed" ?
          -this.offset.scroll.top :
          ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
      ),
      left: (

        // The absolute mouse position
        pageX -

        // Click offset (relative to the element)
        this.offset.click.left -

        // Only for relative positioned nodes: Relative offset from element to offset parent
        this.offset.relative.left -

        // The offsetParent's offset without borders (offset + border)
     is.offset.parent.left +
        ( this.cssPosition === "fixed" ?
          -this.offset.scroll.left :
          ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
      )
    };

  },

  _clear: function() {
    this._removeClass( this.helper, "ui-draggable-dragging" );
    if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
      this.helper.remove();
    }
    this.helper = null;
    this.cancelHelperRemoval = false;
    if ( this.destroyOnClear ) {
      this.destroy();
    }
  },

  // From now on bulk stuff - mainly helpers

  _trigger: function( type, event, ui ) {
    ui = ui || this._uiHash();
    $.ui.plugin.call( this, type, [ event, ui, this ], true );

    // Absolute position and offset (see #6884 ) have to be recalculated after plugins
    if ( /^(drag|start|stop)/.test( type ) ) {
      this.positionAbs = this._convertPositionTo( "absolute" );
      ui.offset = this.positionAbs;
    }
    return $.Widget.prototype._trigger.call( this, type, event, ui );
  },

  plugins: {},

  _uiHash: function() {
    return {
      helper: this.helper,
      position: this.position,
      originalPosition: this.originalPosition,
      offset: this.positionAbs
    };
  }

} );

$.ui.plugin.add( "draggable", "connectToSortable", {
  start: function( event, ui, draggable ) {
    var uiSortable = $.extend( {}, ui, {
      item: draggable.element
    } );

    draggable.sortables = [];
    $( draggable.options.connectToSortable ).each( function() {
      var sortable = $( this ).sortable( "instance" );

      if ( sortable && !sortable.options.disabled ) {
        draggable.sortables.push( sortable );

        // RefreshPositions is called at drag start to refresh the containerCache
        // which is used in drag. This ensures it's initialized and synchronized
        // with any changes that might have happened on the page since initialization.
        sortable.refreshPositions();
        sortable._trigger( "activate", event, uiSortable );
      }
    } );
  },
  stop: function( event, ui, draggable ) {
    var uiSortable = $.extend( {}, ui, {
      item: draggable.element
    } );

    draggable.cancelHelperRemoval = false;

    $.each( draggable.sortables, function() {
      var sortable = this;

      if ( sortable.isOver ) {
        sortable.isOver = 0;

        // Allow this sortable to handle removing the helper
        draggable.cancelHelperRemoval = true;
        sortable.cancelHelperRemoval = false;

        // Use _storedCSS To restore properties in the sortable,
        // as this also handles revert (#9675) since the draggable
        // may have modified them in unexpected ways (#8809)
        sortable._storedCSS = {
          position: sortable.placeholder.css( "position" ),
          top: sortable.placeholder.css( "top" ),
          left: sortable.placeholder.css( "left" )
        };

        sortable._mouseStop( event );

        // Once drag has ended, the sortable should return to using
        // its original helper, not the shared helper from draggable
        sortable.options.helper = sortable.options._helper;
      } else {

        // Prevent this Sortable from removing the helper.
        // However, don't set the draggable to remove the helper
        // either as another connected Sortable may yet handle the removal.
        sortable.cancelHelperRemoval = true;

        sortable._trigger( "deactivate", event, uiSortable );
      }
    } );
  },
  drag: function( event, ui, draggable ) {
    $.each( draggable.sortables, function() {
      var innermostIntersecting = false,
        sortable = this;

      // Copy over variables that sortable's _intersectsWith uses
      sortable.positionAbs = draggable.positionAbs;
      sortable.helperProportions = draggable.helperProportions;
      sortable.offset.click = draggable.offset.click;

      if ( sortable._intersectsWith( sortable.containerCache ) ) {
        innermostIntersecting = true;

        $.each( draggable.sortables, function() {

          // Copy over variables that sortable's _intersectsWith uses
          this.positionAbs = draggable.positionAbs;
          this.helperProportions = draggable.helperProportions;
          this.offset.click = draggable.offset.click;

          if ( this !== sortable &&
              this._intersectsWith( this.containerCache ) &&
              $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
            innermostIntersecting = false;
          }

          return innermostIntersecting;
        } );
      }

      if ( innermostIntersecting ) {

        // If it intersects, we use a little isOver variable and set it once,
        // so that the move-in stuff gets fired only once.
        if ( !sortable.isOver ) {
          sortable.isOver = 1;

          // Store draggable's parent in case we need to reappend to it later.
          draggable._parent = ui.helper.parent();

          sortable.currentItem = ui.helper
            .appendTo( sortable.element )
            .data( "ui-sortable-item", true );

          // Store helper option to later restore it
          sortable.options._helper = sortable.options.helper;

          sortable.options.helper = function() {
            return ui.helper[ 0 ];
          };

          // Fire the start events of the sortable with our passed browser event,
          // and our own helper (so it doesn't create a new one)
          event.target = sortable.currentItem[ 0 ];
          sortable._mouseCapture( event, true );
          sortable._mouseStart( event, true, true );

          // Because the browser event is way off the new appended portlet,
          // modify necessary variables to reflect the changes
          sortable.offset.click.top = draggable.offset.click.top;
          sortable.offset.click.left = draggable.offset.click.left;
          sortable.offset.parent.left -= draggable.offset.parent.left -
            sortable.offset.parent.left;
          sortable.offset.parent.top -= draggable.offset.parent.top -
            sortable.offset.parent.top;

          draggable._trigger( "toSortable", event );

          // Inform draggable that the helper is in a valid drop zone,
          // used solely in the revert option to handle "valid/invalid".
          draggable.dropped = sortable.element;

          // Need to refreshPositions of all sortables in the case that
          // adding to one sortable changes the location of the other sortables (#9675)
          $.each( draggable.sortables, function() {
            this.refreshPositions();
          } );

          // Hack so receive/update callbacks work (mostly)
          draggable.currentItem = draggable.element;
          sortable.fromOutside = draggable;
        }

        if ( sortable.currentItem ) {
          sortable._mouseDrag( event );

          // Copy the sortable's position because the draggable's can potentially reflect
          // a relative position, while sortable is always absolute, which the dragged
          // element has now become. (#8809)
          ui.position = sortable.position;
        }
      } else {

        // If it doesn't intersect with the sortable, and it intersected before,
        // we fake the drag stop of the sortable, but make sure it doesn't remove
        // the helper by using cancelHelperRemoval.
        if ( sortable.isOver ) {

          sortable.isOver = 0;
          sortable.cancelHelperRemoval = true;

          // Calling sortable's mouseStop would trigger a revert,
          // so revert must be temporarily false until after mouseStop is called.
          sortable.options._revert = sortable.options.revert;
          sortable.options.revert = false;

          sortable._trigger( "out", event, sortable._uiHash( sortable ) );
          sortable._mouseStop( event, true );

          // Restore sortable behaviors that were modfied
          // when the draggable entered the sortable area (#9481)
          sortable.options.revert = sortable.options._revert;
          sortable.options.helper = sortable.options._helper;

          if ( sortable.placeholder ) {
            sortable.placeholder.remove();
          }

          // Restore and recalculate tggable's offset considering the sortable
          // may have modified them in unexpected ways. (#8809, #10669)
          ui.helper.appendTo( draggable._parent );
          draggable._refreshOffsets( event );
          ui.position = draggable._generatePosition( event, true );

          draggable._trigger( "fromSortable", event );

          // Inform draggable that the helper is no longer in a valid drop zone
          draggable.dropped = false;

          // Need to refreshPositions of all sortables just in case removing
          // from one sortable changes the location of other sortables (#9675)
          $.each( draggable.sortables, function() {
            this.refreshPositions();
          } );
        }
      }
    } );
  }
} );

$.ui.plugin.add( "draggable", "cursor", {
  start: function( event, ui, instance ) {
    var t = $( "body" ),
      o = instance.options;

    if ( t.css( "cursor" ) ) {
      o._cursor = t.css( "cursor" );
    }
    t.css( "cursor", o.cursor );
  },
  stop: function( event, ui, instance ) {
    var o = instance.options;
    if ( o._cursor ) {
      $( "body" ).css( "cursor", o._cursor );
    }
  }
} );

$.ui.plugin.add( "draggable", "opacity", {
  start: function( event, ui, instance ) {
    var t = $( ui.helper ),
      o = instance.options;
    if ( t.css( "opacity" ) ) {
      o._opacity = t.css( "opacity" );
    }
    t.css( "opacity", o.opacity );
  },
  stop: function( event, ui, instance ) {
    var o = instance.options;
    if ( o._opacity ) {
      $( ui.helper ).css( "opacity", o._opacity );
    }
  }
} );

$.ui.plugin.add( "draggable", "scroll", {
  start: function( event, ui, i ) {
    if ( !i.scrollParentNotHidden ) {
      i.scrollParentNotHidden = i.helper.scrollParent( false );
    }

    if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
        i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
      i.overflowOffset = i.scrollParentNotHidden.offset();
    }
  },
  drag: function( event, ui, i  ) {

    var o = i.options,
      scrolled = false,
      scrollParent = i.scrollParentNotHidden[ 0 ],
      document = i.document[ 0 ];

    if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
      if ( !o.axis || o.axis !== "x" ) {
        if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
            o.scrollSensitivity ) {
          scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
        } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
          scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
        }
      }

      if ( !o.axis || o.axis !== "y" ) {
        if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
            o.scrollSensitivity ) {
          scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
        } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
          scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
        }
      }

    } else {

      if ( !o.axis || o.axis !== "x" ) {
        if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
          scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
        } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
            o.scrollSensitivity ) {
          scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
        }
      }

      if ( !o.axis || o.axis !== "y" ) {
        if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
          scrolled = $( document ).scrollLeft(
            $( document ).scrollLeft() - o.scrollSpeed
          );
        } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
            o.scrollSensitivity ) {
          scrolled = $( document ).scrollLeft(
            $( document ).scrollLeft() + o.scrollSpeed
          );
        }
      }

    }

    if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
      $.ui.ddmanager.prepareOffsets( i, event );
    }

  }
} );

$.ui.plugin.add( "draggable", "snap", {
  start: function( event, ui, i ) {

    var o = i.options;

    i.snapElements = [];

    $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
      .each( function() {
        var $t = $( this ),
          $o = $t.offset();
        if ( this !== i.element[ 0 ] ) {
          i.snapElements.push( {
            item: this,
            width: $t.outerWidth(), height: $t.outerHeight(),
            top: $o.top, left: $o.left
          } );
        }
      } );

  },
  drag: function( event, ui, inst ) {

    var ts, bs, ls, rs, l, r, t, b, i, first,
      o = inst.options,
      d = o.snapTolerance,
      x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
      y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;

    for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {

      l = inst.snapElements[ i ].left - inst.margins.left;
      r = l + inst.snapElements[ i ].width;
      t = inst.snapElements[ i ].top - inst.margins.top;
      b = t + inst.snapElements[ i ].height;

      if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
          !$.contains( inst.snapElements[ i ].item.ownerDocument,
          inst.snapElements[ i ].item ) ) {
        if ( inst.snapElements[ i ].snapping ) {
          ( inst.options.snap.release &&
            inst.options.snap.release.call(
              inst.element,
              event,
              $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
            ) );
        }
        inst.snapElements[ i ].snapping = false;
        continue;
      }

      if ( o.snapMode !== "inner" ) {
        ts = Math.abs( t - y2 ) <= d;
        bs = Math.abs( b - y1 ) <= d;
        ls = Math.abs( l - x2 ) <= d;
        rs = Math.abs( r - x1 ) <= d;
        if ( ts ) {
          ui.position.top = inst._convertPositionTo( "relative", {
            top: t - inst.helperProportions.height,
            left: 0
          } ).top;
        }
        if ( bs ) {
          ui.position.top = inst._convertPositionTo( "relative", {
            top: b,
            left: 0
          } ).top;
        }
        if ( ls ) {
          ui.position.left = inst._convertPositionTo( "relative", {
            top: 0,
            left: l - inst.helperProportions.width
          } ).left;
        }
        if ( rs ) {
          ui.position.left = inst._convertPositionTo( "relative", {
            top: 0,
            left: r
          } ).left;
        }
      }

      first = ( ts || bs || ls || rs );

      if ( o.snapMode !== "outer" ) {
        ts = Math.abs( t - y1 ) <= d;
        bs = Math.abs( b - y2 ) <= d;
        ls = Math.abs( l - x1 ) <= d;
        rs = Math.abs( r - x2 ) <= d;
        if ( ts ) {
          ui.position.top = inst._convertPositionTo( "relative", {
            top: t,
            left: 0
          } ).top;
        }
        if ( bs ) {
          ui.position.top = inst._convertPositionTo( "relative", {
            top: b - inst.helperProportions.height,
            left: 0
          } ).top;
        }
        if ( ls ) {
          ui.position.left = inst._convertPositionTo( "relative", {
            top: 0,
            left: l
          } ).left;
        }
        if ( rs ) {
          ui.position.left = inst._convertPositionTo( "relative", {
            top: 0,
            left: r - inst.helperProportions.width
          } ).left;
        }
      }

      if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
        ( inst.options.snap.snap &&
          inst.options.snap.snap.call(
            inst.element,
            event,
            $.extend( inst._uiHash(), {
              snapItem: inst.snapElements[ i ].item
            } ) ) );
      }
      inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );

    }

  }
} );

$.ui.plugin.add( "draggable", "stack", {
  start: function( event, ui, instance ) {
    var min,
      o = instance.options,
      group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
        return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
          ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
      } );

    if ( !group.length ) { return; }

    min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
    $( group ).each( function( i ) {
      $( this ).css( "zIndex", min + i );
    } );
    this.css( "zIndex", ( min + group.length ) );
  }
} );

$.ui.plugin.add( "draggable", "zIndex", {
  start: function( event, ui, instance ) {
    var t = $( ui.helper ),
      o = instance.options;

    if ( t.css( "zIndex" ) ) {
      o._zIndex = t.css( "zIndex" );
    }
    t.css( "zIndex", o.zIndex );
  },
  stop: function( event, ui, instance ) {
    var o = instance.options;

    if ( o._zIndex ) {
      $( ui.helper ).css( "zIndex", o._zIndex );
    }
  }
} );

var widgetsDraggable = $.ui.draggable;


/*!
 * jQuery UI Droppable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Droppable
//>>group: Interactions
//>>description: Enables drop targets for draggable elements.
//>>docs: http://api.jqueryui.com/droppable/
//>>demos: http://jqueryui.com/droppable/



$.widget( "ui.droppable", {
  version: "1.12.1",
  widgetEventPrefix: "drop",
  options: {
    accept: "*",
    addClasses: true,
    greedy: false,
    scope: "default",
    tolerance: "intersect",

    // Callbacks
    activate: null,
    deactivate: null,
    drop: null,
    out: null,
    over: null
  },
  _create: function() {

    var proportions,
      o = this.options,
      accept = o.accept;

    this.isover = false;
    this.isout = true;

    this.accept = $.isFunction( accept ) ? accept : function( d ) {
      return d.is( accept );
    };

    this.proportions = function( /* valueToWrite */ ) {
      if ( arguments.length ) {

        // Store the droppable's proportions
        proportions = arguments[ 0 ];
      } else {

        // Retrieve or derive the droppable's proportions
        return proportions ?
          proportions :
          proportions = {
            width: this.element[ 0 ].offsetWidth,
            height: this.element[ 0 ].offsetHeight
          };
      }
    };

    this._addToManager( o.scope );

    o.addClasses && this._addClass( "ui-droppable" );

  },

  _addToManager: function( scope ) {

    // Add the reference and positions to the manager
    $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
    $.ui.ddmanager.droppables[ scope ].push( this );
  },

  _splice: function( drop ) {
    var i = 0;
    for ( ; i < drop.length; i++ ) {
      if ( drop[ i ] === this ) {
        drop.splice( i, 1 );
      }
    }
  },

  _destroy: function() {
    var drop = $.ui.ddmanager.droppables[ this.options.scope ];

    this._splice( drop );
  },

  _setOption: function( key, value ) {

    if ( key === "accept" ) {
      this.accept = $.isFunction( value ) ? value : function( d ) {
        return d.is( value );
      };
    } else if ( key === "scope" ) {
      var drop = $.ui.ddmanager.droppables[ this.options.scope ];

      this._splice( drop );
      this._addToManager( value );
    }

    this._super( key, value );
  },

  _activate: function( event ) {
    var draggable = $.ui.ddmanager.current;

    this._addActiveClass();
    if ( draggable ) {
      this._trigger( "activate", event, this.ui( draggable ) );
    }
  },

  _deactivate: function( event ) {
    var draggable = $.ui.ddmanager.current;

    this._removeActiveClass();
    if ( draggable ) {
      this._trigger( "deactivate", event, this.ui( draggable ) );
    }
  },

  _over: function( event ) {

    var draggable = $.ui.ddmanager.current;

    // Bail if draggable and droppable are same element
    if ( !draggable || ( draggable.currentItem ||
        draggable.element )[ 0 ] === this.element[ 0 ] ) {
      return;
    }

    if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
        draggable.element ) ) ) {
      this._addHoverClass();
      this._trigger( "over", event, this.ui( draggable ) );
    }

  },

  _out: function( event ) {

    var draggable = $.ui.ddmanager.current;

    // Bail if draggable and droppable are same element
    if ( !draggable || ( draggable.currentItem ||
        draggable.element )[ 0 ] === this.element[ 0 ] ) {
      return;
    }

    if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
        draggable.element ) ) ) {
      this._removeHoverClass();
      this._trigger( "out", event, this.ui( draggable ) );
    }

  },

  _drop: function( event, custom ) {

    var draggable = custom || $.ui.ddmanager.current,
      childrenIntersection = false;

    // Bail if draggable and droppable are same element
    if ( !draggable || ( draggable.currentItem ||
        draggable.element )[ 0 ] === this.element[ 0 ] ) {
      return false;
    }

    this.element
      .find( ":data(ui-droppable)" )
      .not( ".ui-draggable-dragging" )
      .each( function() {
        var inst = $( this ).droppable( "instance" );
        if (
          inst.options.greedy &&
          !inst.options.disabled &&
          inst.options.scope === draggable.options.scope &&
          inst.accept.call(
            inst.element[ 0 ], ( draggable.currentItem || draggable.element )
          ) &&
          intersect(
            draggable,
            $.extend( inst, { offset: inst.element.offset() } ),
            inst.options.tolerance, event
          )
        ) {
          childrenIntersection = true;
          return false; }
      } );
    if ( childrenIntersection ) {
      return false;
    }

    if ( this.accept.call( this.element[ 0 ],
        ( draggable.currentItem || draggable.element ) ) ) {
      this._removeActiveClass();
      this._removeHoverClass();

      this._trigger( "drop", event, this.ui( draggable ) );
      return this.element;
    }

    return false;

  },

  ui: function( c ) {
    return {
      draggable: ( c.currentItem || c.element ),
      helper: c.helper,
      position: c.position,
      offset: c.positionAbs
    };
  },

  // Extension points just to make backcompat sane and avoid duplicating logic
  // TODO: Remove in 1.13 along with call to it below
  _addHoverClass: function() {
    this._addClass( "ui-droppable-hover" );
  },

  _removeHoverClass: function() {
    this._removeClass( "ui-droppable-hover" );
  },

  _addActiveClass: function() {
    this._addClass( "ui-droppable-active" );
  },

  _removeActiveClass: function() {
    this._removeClass( "ui-droppable-active" );
  }
} );

var intersect = $.ui.intersect = ( function() {
  function isOverAxis( x, reference, size ) {
    return ( x >= reference ) && ( x < ( reference + size ) );
  }

  return function( draggable, droppable, toleranceMode, event ) {

    if ( !droppable.offset ) {
      return false;
    }

    var x1 = ( draggable.positionAbs ||
        draggable.position.absolute ).left + draggable.margins.left,
      y1 = ( draggable.positionAbs ||
        draggable.position.absolute ).top + draggable.margins.top,
      x2 = x1 + draggable.helperProportions.width,
      y2 = y1 + draggable.helperProportions.height,
      l = droppable.offset.left,
      t = droppable.offset.top,
      r = l + droppable.proportions().width,
      b = t + droppable.proportions().height;

    switch ( toleranceMode ) {
    case "fit":
      return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
    case "intersect":
      return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
        x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
        t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
        y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
    case "pointer":
      return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
        isOverAxis( event.pageX, l, droppable.proportions().width );
    case "touch":
      return (
        ( y1 >= t && y1 <= b ) || // Top edge touching
        ( y2 >= t && y2 <= b ) || // Bottom edge touching
        ( y1 < t && y2 > b ) // Surrounded vertically
      ) && (
        ( x1 >= l && x1 <= r ) || // Left edge touching
        ( x2 >= l && x2 <= r ) || // Right edge touching
        ( x1 < l && x2 > r ) // Surrounded horizontally
      );
    default:
      return false;
    }
  };
} )();

/*
  This manager tracks offsets of draggables and droppables
*/
$.ui.ddmanager = {
  current: null,
  droppables: { "default": [] },
  prepareOffsets: function( t, event ) {

    var i, j,
      m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
      type = event ? event.type : null, // workaround for #2317
      list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();

    droppablesLoop: for ( i = 0; i < m.length; i++ ) {

      // No disabled and non-accepted
      if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
          ( t.currentItem || t.element ) ) ) ) {
        continue;
      }

      // Filter out elements in the current dragged item
      for ( j = 0; j < list.length; j++ ) {
        if ( list[ j ] === m[ i ].element[ 0 ] ) {
          m[ i ].proportions().height = 0;
          continue droppablesLoop;
        }
      }

      m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
      if ( !m[ i ].visible ) {
        continue;
      }

      // Activate the droppable if used directly from draggables
      if ( type === "mousedown" ) {
        m[ i ]._activate.call( m[ i ], event );
      }

      m[ i ].offset = m[ i ].element.offset();
      m[ i ].proportions( {
        width: m[ i ].element[ 0 ].offsetWidth,
        height: m[ i ].element[ 0 ].offsetHeight
      } );

    }

  },
  drop: function( draggable, event ) {

    var dropped = false;

    // Create a copy of the droppables in case the list changes during the drop (#9116)
    $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {

      if ( !this.options ) {
        return;
      }
      if ( !this.options.disabled && this.visible &&
          intersect( draggable, this, this.options.tolerance, event ) ) {
        dropped = this._drop.call( this, event ) || dropped;
      }

      if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
          ( draggable.currentItem || draggable.element ) ) ) {
        this.isout = true;
        this.isover = false;
        this._deactivate.call( this, event );
      }

    } );
    return dropped;

  },
  dragStart: function( draggable, event ) {

    // Listen for scrolling so that if the dragging causes scrolling the position of the
    // droppables can be recalculated (see #5003)
    draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
      if ( !draggable.options.refreshPositions ) {
        $.ui.ddmanager.prepareOffsets( draggable, event );
      }
    } );
  },
  drag: function( draggable, event ) {

    // If you have a highly dynamic page, you might try this option. It renders positions
    // every time you move the mouse.
    if ( draggable.options.refreshPositions ) {
      $.ui.ddmanager.prepareOffsets( draggable, event );
    }

    // Run through all droppables and check their positions based on specific tolerance options
    $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {

      if ( this.options.disabled || this.greedyChild || !this.visible ) {
        return;
      }

      var parentInstance, scope, parent,
        intersects = intersect( draggable, this, this.options.tolerance, event ),
        c = !intersects && this.isover ?
          "isout" :
          ( intersects && !this.isover ? "isover" : null );
      if ( !c ) {
        return;
      }

      if ( this.options.greedy ) {

        // find droppable parents with same scope
        scope = this.options.scope;
        parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
          return $( this ).droppable( "instance" ).options.scope === scope;
        } );

        if ( parent.length ) {
          parentInstance = $( parent[ 0 ] ).droppablinstance" );
          parentInstance.greedyChild = ( c === "isover" );
        }
      }

      // We just moved into a greedy child
      if ( parentInstance && c === "isover" ) {
        parentInstance.isover = false;
        parentInstance.isout = true;
        parentInstance._out.call( parentInstance, event );
      }

      this[ c ] = true;
      this[ c === "isout" ? "isover" : "isout" ] = false;
      this[ c === "isover" ? "_over" : "_out" ].call( this, event );

      // We just moved out of a greedy child
      if ( parentInstance && c === "isout" ) {
        parentInstance.isout = false;
        parentInstance.isover = true;
        parentInstance._over.call( parentInstance, event );
      }
    } );

  },
  dragStop: function( draggable, event ) {
    draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );

    // Call prepareOffsets one final time since IE does not fire return scroll events when
    // overflow was caused by drag (see #5003)
    if ( !draggable.options.refreshPositions ) {
      $.ui.ddmanager.prepareOffsets( draggable, event );
    }
  }
};

// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {

  // Backcompat for activeClass and hoverClass options
  $.widget( "ui.droppable", $.ui.droppable, {
    options: {
      hoverClass: false,
      activeClass: false
    },
    _addActiveClass: function() {
      this._super();
      if ( this.options.activeClass ) {
        this.element.addClass( this.options.activeClass );
      }
    },
    _removeActiveClass: function() {
      this._super();
      if ( this.options.activeClass ) {
        this.element.removeClass( this.options.activeClass );
      }
    },
    _addHoverClass: function() {
      this._super();
      if ( this.options.hoverClass ) {
        this.element.addClass( this.options.hoverClass );
      }
    },
    _removeHoverClass: function() {
      this._super();
      if ( this.options.hoverClass ) {
        this.element.removeClass( this.options.hoverClass );
      }
    }
  } );
}

var widgetsDroppable = $.ui.droppable;


/*!
 * jQuery UI Resizable 1.12.1
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 */

//>>label: Resizable
//>>group: Interactions
//>>description: Enables resize functionality for any element.
//>>docs: http://api.jqueryui.com/resizable/
//>>demos: http://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css



$.widget( "ui.resizable", $.ui.mouse, {
  version: "1.12.1",
  widgetEventPrefix: "resize",
  options: {
    alsoResize: false,
    animate: false,
    animateDuration: "slow",
    animateEasing: "swing",
    aspectRatio: false,
    autoHide: false,
    classes: {
      "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
    },
    containment: false,
    ghost: false,
    grid: false,
    handles: "e,s,se",
    helper: false,
    maxHeight: null,
    maxWidth: null,
    minHeight: 10,
    minWidth: 10,

    // See #7960
    zIndex: 90,

    // Callbacks
    resize: null,
    start: null,
    stop: null
  },

  _num: function( value ) {
    return parseFloat( value ) || 0;
  },

  _isNumber: function( value ) {
    return !isNaN( parseFloat( value ) );
  },

  _hasScroll: function( el, a ) {

    if ( $( el ).css( "overflow" ) === "hidden" ) {
      return false;
    }

    var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
      has = false;

    if ( el[ scroll ] > 0 ) {
      return true;
    }

    // TODO: determine which cases actually cause this to happen
    // if the element doesn't have the scroll set, see if it's possible to
    // set the scroll
    el[ scroll ] = 1;
    has = ( el[ scroll ] > 0 );
    el[ scroll ] = 0;
    return has;
  },

  _create: function() {

    var margins,
      o = this.options,
      that = this;
    this._addClass( "ui-resizable" );

    $.extend(this, {
      _aspectRatio: !!( o.aspectRatio ),
      aspectRatio: o.aspectRatio,
      originalElement: this.element,
      _proportionallyResizeElements: [],
      _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
    } );

    // Wrap the element if it cannot hold child nodes
    if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {

      this.element.wrap(
        $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
          position: this.element.css( "position" ),
          width: this.element.outerWidth(),
          height: this.element.outerHeight(),
          top: this.element.css( "top" ),
          left: this.element.css( "left" )
        } )
      );

      this.element = this.element.parent().data(
        "ui-resizable", this.element.resizable( "instance" )
      );

      this.elementIsWrapper = true;

      margins = {
        marginTop: this.originalElement.css( "marginTop" ),
        marginRight: this.originalElement.css( "marginRight" ),
        marginBottom: this.originalElement.css( "marginBottom" ),
        marginLeft: this.originalElement.css( "marginLeft" )
      };

      this.element.css( margins );
      this.originalElement.css( "margin", 0 );

      // support: Safari
      // Prevent Safari textarea resize
      this.originalResizeStyle = this.originalElement.css( "resize" );
      this.originalElement.css( "resize", "none" );

      this._proportionallyResizeElements.push( this.originalElement.css( {
        position: "static",
        zoom: 1,
        display: "block"
      } ) );

      // Support: IE9
      // avoid IE jump (hard set the margin)
      this.originalElement.css( margins );

      this._proportionallyResize();
    }

    this._setupHandles();

    if ( o.autoHide ) {
      $( this.element )
        .on( "mouseenter", function() {
          if ( o.disabled ) {
            return;
          }
          that._removeClass( "ui-resizable-autohide" );
          that._handles.show();
        } )
        .on( "mouseleave", function() {
          if ( o.disabled ) {
            return;
          }
          if ( !that.resizing ) {
            that._addClass( "ui-resizable-autohide" );
            that._handles.hide();
          }
        } );
    }

    this._mouseInit();
  },

  _destroy: function() {

    this._mouseDestroy();

    var wrapper,
      _destroy = function( exp ) {
        $( exp )
          .removeData( "resizable" )
          .removeData( "ui-resizable" )
          .off( ".resizable" )
          .find( ".ui-resizable-handle" )
            .remove();
      };

    // TODO: Unwrap at same DOM position
    if ( this.elementIsWrapper ) {
      _destroy( this.element );
      wrapper = this.element;
      this.originalElement.css( {
        position: wrapper.css( "position" ),
        width: wrapper.outerWidth(),
        height: wrapper.outerHeight(),
        top: wrapper.css( "top" ),
        left: wrapper.css( "left" )
      } ).insertAfter( wrapper );
      wrapper.remove();
    }

    this.originalElement.css( "resize", this.originalResizeStyle );
    _destroy( this.originalElement );

    return this;
  },

  _setOption: function( key, value ) {
    this._super( key, value );

    switch ( key ) {
    case "handles":
      this._removeHandles();
      this._setupHandles();
      break;
    default:
      break;
    }
  },

  _setupHandles: function() {
    var o = this.options, handle, i, n, hname, axis, that = this;
    this.handles = o.handles ||
      ( !$( ".ui-resizable-handle", this.element ).length ?
        "e,s,se" : {
          n: ".ui-resizable-n",
          e: ".ui-resizable-e",
          s: ".ui-resizable-s",
          w: ".ui-resizable-w",
          se: ".ui-resizable-se",
          sw: ".ui-resizable-sw",
          ne: ".ui-resizable-ne",
          nw: ".ui-resizable-nw"
        } );

    this._handles = $();
    if ( this.handles.constructor === String ) {

      if ( this.handles === "all" ) {
        this.handles = "n,e,s,w,se,sw,ne,nw";
      }

      n = this.handles.split( "," );
      this.handles = {};

      for ( i = 0; i < n.length; i++ ) {

        handle = $.trim( n[ i ] );
        hname = "ui-resizable-" + handle;
        axis = $( "<div>" );
        this._addClass( axis, "ui-resizable-handle " + hname );

        axis.css( { zIndex: o.zIndex } );

        this.handles[ handle ] = ".ui-resizable-" + handle;
        this.element.append( axis );
      }

    }

    this._renderAxis = function( target ) {

      var i, axis, padPos, padWrapper;

      target = target || this.element;

      for ( i in this.handles ) {

        if ( this.handles[ i ].constructor === String ) {
          this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
        } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
          this.handles[ i ] = $( this.handles[ i ] );
          this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
        }

        if ( this.elementIsWrapper &&
            this.originalElement[ 0 ]
              .nodeName
              .match( /^(textarea|input|select|button)$/i ) ) {
          axis = $( this.handles[ i ], this.element );

          padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
            axis.outerHeight() :
            axis.outerWidth();

          padPos = [ "padding",
            /ne|nw|n/.test( i ) ? "Top" :
            /se|sw|s/.test( i ) ? "Bottom" :
            /^e$/.test( i ) ? "Right" : "Left" ].join( "" );

          target.css( padPos, padWrapper );

          this._proportionallyResize();
        }

        this._handles = this._handles.add( this.handles[ i ] );
      }
    };

    // TODO: make renderAxis a prototype function
    this._renderAxis( this.element );

    this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
    this._handles.disableSelection();

    this._handles.on( "mouseover", function() {
      if ( !that.resizing ) {
        if ( this.className ) {
          axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
        }
        that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
      }
    } );

    if ( o.autoHide ) {
      this._handles.hide();
      this._addClass( "ui-resizable-autohide" );
    }
  },

  _removeHandles: function() {
    this._handles.remove();
  },

  _mouseCapture: function( event ) {
    var i, handle,
      capture = false;

    for ( i in this.handles ) {
      handle = $( this.handles[ i ] )[ 0 ];
      if ( handle === event.target || $.contains( handle, event.target ) ) {
        capture = true;
      }
    }

    return !this.options.disabled && capture;
  },

  _mouseStart: function( event ) {

    var curleft, curtop, cursor,
      o = this.options,
      el = this.element;

    this.resizing = true;

    this._renderProxy();

    curleft = this._num( this.helper.css( "left" ) );
    curtop = this._num( this.helper.css( "top" ) );

    if ( o.containment ) {
      curleft += $( o.containment ).scrollLeft() || 0;
      curtop += $( o.containment ).scrollTop() || 0;
    }

    this.offset = this.helper.offset();
    this.position = { left: curleft, top: curtop };

    this.size = this._helper ? {
        width: this.helper.width(),
        height: this.helper.height()
      } : {
        width: el.width(),
        height: el.height()
      };

    this.originalSize = this._helper ? {
        width: el.outerWidth(),
        height: el.outerHeight()
      } : {
        width: el.width(),
        height: el.height()
      };

    this.sizeDiff = {
      width: el.outerWidth() - el.width(),
      height: el.outerHeight() - el.height()
    };

    this.originalPosition = { left: curleft, top: curtop };
    this.originalMousePosition = { left: event.pageX, top: event.pageY };

    this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
      o.aspectRatio :
      ( ( this.originalSize.width / this.originalSize.height ) || 1 );

    cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
    $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );

    this._addClass( "ui-resizable-resizing" );
    this._propagate( "start", event );
    return true;
  },

  _mouseDrag: function( event ) {

    var data, props,
      smp = this.originalMousePosition,
      a = this.axis,
      dx = ( event.pageX - smp.left ) || 0,
      dy = ( event.pageY - smp.top ) || 0,
      trigger = this._change[ a ];

    this._updatePrevProperties();

    if ( !trigger ) {
      return false;
    }

    data = trigger.apply( this, [ event, dx, dy ] );

    this._updateVirtualBoundaries( event.shiftKey );
    if ( this._aspectRatio || event.shiftKey ) {
      data = this._updateRatio( data, event );
    }

    data = this._respectSize( data, event );

    this._updateCache( data );

    this._propagate( "resize", event );

    props = this._applyChanges();

    if ( !this._helper && this._proportionallyResizeElements.length ) {
      this._proportionallyResize();
    }

    if ( !$.isEmptyObject( props ) ) {
      this._updatePrevProperties();
      this._trigger( "resize", event, this.ui() );
      this._applyChanges();
    }

    return false;
  },

  _mouseStop: function( event ) {

    this.resizing = false;
    var pr, ista, soffseth, soffsetw, s, left, top,
      o = this.options, that = this;

    if ( this._helper ) {

      pr = this._proportionallyResizeElements;
      ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
      soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
      soffsetw = ista ? 0 : that.sizeDiff.width;

      s = {
        width: ( that.helper.width()  - soffsetw ),
        height: ( that.helper.height() - soffseth )
      };
      left = ( parseFloat( that.element.css( "left" ) ) +
        ( that.position.left - that.originalPosition.left ) ) || null;
      top = ( parseFloat( that.element.css( "top" ) ) +
        ( that.position.top - that.originalPosition.top ) ) || null;

      if ( !o.animate ) {
        this.element.css( $.extend( s, { top: top, left: left } ) );
      }

      that.helper.height( that.size.height );
      that.helper.width( that.size.width );

      if ( this._helper && !o.animate ) {
        this._proportionallyResize();
      }
    }

    $( "body" ).css( "cursor", "auto" );

    this._removeClass( "ui-resizable-resizing" );

    this._propagate( "stop", event );

    if ( this._helper ) {
      this.helper.remove();
    }

    return false;

  },

  _updatePrevProperties: function() {
    this.prevPosition = {
      top: this.position.top,
      left: this.position.left
    };
    this.prevSize = {
      width: this.size.width,
      height: this.size.height
    };
  },

  _applyChanges: function() {
    var props = {};

    if ( this.position.top !== this.prevPosition.top ) {
      props.top = this.position.top + "px";
    }
    if ( this.position.left !== this.prevPosition.left ) {
      props.left = this.position.left + "px";
    }
    if ( this.size.width !== this.prevSize.width ) {
      props.width = this.size.width + "px";
    }
    if ( this.size.height !== this.prevSize.height ) {
      props.height = this.size.height + "px";
    }

    this.helper.css( props );

    return props;
  },

  _updateVirtualBoundaries: function( forceAspectRatio ) {
    var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
      o = this.options;

    b = {
      minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
      maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
      minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
      maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
    };

    if ( this._aspectRatio || forceAspectRatio ) {
      pMinWidth = b.minHeight * this.aspectRatio;
      pMinHeight = b.minWidth / this.aspectRatio;
      pMaxWidth = b.maxHeight * this.aspectRatio;
      pMaxHeight = b.maxWidth / this.aspectRatio;

      if ( pMinWidth > b.minWidth ) {
        b.minWidth = pMinWidth;
      }
      if ( pMinHeight > b.minHeight ) {
        b.minHeight = pMinHeight;
      }
      if ( pMaxWidth < b.maxWidth ) {
        b.maxWidth = pMaxWidth;
      }
      if ( pMaxHeight < b.maxHeight ) {
        b.maxHeight = pMaxHeight;
      }
    }
    this._vBoundaries = b;
  },

  _updateCache: function( data ) {
    this.offset = this.helper.offset();
    if ( this._isNumber( data.left ) ) {
      this.position.left = data.left;
    }
    if ( this._isNumber( data.top ) ) {
      this.position.top = data.top;
    }
    if ( this._isNumber( data.height ) ) {
      this.size.height = data.height;
    }
    if ( this._isNumber( data.width ) ) {
      this.size.width = data.width;
    }
  },

  _updateRatio: function( data ) {

    var cpos = this.position,
      csize = this.size,
      a = this.axis;

    if ( this._isNumber( data.height ) ) {
      data.width = ( data.height * this.aspectRatio );
    } else if ( this._isNumber( data.width ) ) {
      data.height = ( data.width / this.aspectRatio );
    }

    if ( a === "sw" ) {
      data.left = cpos.left + ( csize.width - data.width );
      data.top = null;
    }
    if ( a === "nw" ) {
      data.top = cpos.top + ( csize.height - data.height );
      data.left = cpos.left + ( csize.width - data.width );
    }

    return data;
  },

  _respectSize: function( data ) {

    var o = this._vBoundaries,
      a = this.axis,
      ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
      ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
      isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
      isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
      dw = this.originalPosition.left + this.originalSize.width,
      dh = this.originalPosition.top + this.originalSize.height,
      cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
    if ( isminw ) {
      data.width = o.minWidth;
    }
    if ( isminh ) {
      data.height = o.minHeight;
    }
    if ( ismaxw ) {
      data.width = o.maxWidth;
    }
    if ( ismaxh ) {
      data.height = o.maxHeight;
    }

    if ( isminw && cw ) {
      data.left = dw - o.minWidth;
    }
    if ( ismaxw && cw ) {
      data.left = dw - o.maxWidth;
    }
    if ( isminh && ch ) {
      data.top = dh - o.minHeight;
    }
    if ( ismaxh && ch ) {
      data.top = dh - o.maxHeight;
    }

    // Fixing jump error on top/left - bug #2330
    if ( !data.width && !data.height && !data.left && data.top ) {
      data.top = null;
    } else if ( !data.width && !data.height && !data.top && data.left ) {
      data.left = null;
    }

    return data;
  },

  _getPaddingPlusBorderDimensions: function( element ) {
    var i = 0,
      widths = [],
      borders = [
        element.css( "borderTopWidth" ),
        element.css( "borderRightWidth" ),
        element.css( "borderBottomWidth" ),
        element.css( "borderLeftWidth" )
      ],
      paddings = [
        element.css( "paddingTop" ),
        element.css( "paddingRight" ),
        element.css( "paddingBottom" ),
        element.css( "paddingLeft" )
      ];

    for ( ; i < 4; i++ ) {
      widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
      widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
    }

    return {
      height: widths[ 0 ] + widths[ 2 ],
      width: widths[ 1 ] + widths[ 3 ]
    };
  },

  _proportionallyResize: function() {

    if ( !this._proportionallyResizeElements.length ) {
      return;
    }

    var prel,
      i = 0,
      element = this.helper || this.element;

    for ( ; i < this._proportionallyResizeElements.length; i++ ) {

      prel = this._proportionallyResizeElements[ i ];

      // TODO: Seems like a bug to cache this.outerDimensions
      // considering that we are in a loop.
      if ( !this.outerDimensions ) {
        this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
      }

      prel.css( {
        height: ( element.height() - this.outerDimensions.height ) || 0,
        width: ( element.width() - this.outerDimensions.width ) || 0
      } );

    }

  },

  _renderProxy: function() {

    var el = this.element, o = this.options;
    this.elementOffset = el.offset();

    if ( this._helper ) {

      this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );

      this._addClass( this.helper, this._helper );
      this.helper.css( {
        width: this.element.outerWidth(),
        height: this.element.outerHeight(),
        position: "absolute",
        left: this.elementOffset.left + "px",
        top: this.elementOffset.top + "px",
        zIndex: ++o.zIndex //TODO: Don't modify option
      } );

      this.helper
        .appendTo( "body" )
        .disableSelection();

    } else {
      this.helper = this.element;
    }

  },

  _change: {
    e: function( event, dx ) {
      return { width: this.originalSize.width + dx };
    },
    w: function( event, dx ) {
      var cs = this.originalSize, sp = this.originalPosition;
      return { left: sp.left + dx, width: cs.width - dx };
    },
    n: function( event, dx, dy ) {
      var cs = this.originalSize, sp = this.originalPosition;
      return { top: sp.top + dy, height: cs.height - dy };
    },
    s: function( event, dx, dy ) {
      return { height: this.originalSize.height + dy };
    },
    se: function( event, dx, dy ) {
      return $.extend( this._change.s.apply( this, arguments ),
        this._change.e.apply( this, [ event, dx, dy ] ) );
    },
    sw: function( event, dx, dy ) {
      return $.extend( this._change.s.apply( this, arguments ),
        this._change.w.apply( this, [ event, dx, dy ] ) );
    },
    ne: function( event, dx, dy ) {
      return $.extend( this._change.n.apply( this, arguments ),
        this._change.e.apply( this, [ event, dx, dy ] ) );
    },
    nw: function( event, dx, dy ) {
      return $.extend( this._change.n.apply( this, arguments ),
        this._change.w.apply( this, [ event, dx, dy ] ) );
    }
  },

  _propagate: function( n, event ) {
    $.ui.plugin.call( this, n, [ event, this.ui() ] );
    ( n !== "resize" && this._trigger( n, event, this.ui() ) );
  },

  plugins: {},

  ui: function() {
    return {
      originalElement: this.originalElement,
      element: this.element,
      helper: this.helper,
      position: this.position,
      size: this.size,
      originalSize: this.originalSize,
      originalPosition: this.originalPosition
    };
  }

} );

/*
 * Resizable Extensions
 */

$.ui.plugin.add( "resizable", "animate", {

  stop: function( event ) {
    var that = $( this ).resizable( "instance" ),
      o = that.options,
      pr = that._proportionallyResizeElements,
      ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
      soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
      soffsetw = ista ? 0 : that.sizeDiff.width,
      style = {
        width: ( that.size.width - soffsetw ),
        height: ( that.size.height - soffseth )
      },
      left = ( parseFloat( that.element.css( "left" ) ) +
        ( that.position.left - that.originalPosition.left ) ) || null,
      top = ( parseFloat( that.element.css( "top" ) ) +
        ( that.position.top - that.originalPosition.top ) ) || null;

    that.element.animate(
      $.extend( style, top && left ? { top: top, left: left } : {} ), {
        duration: o.animateDuration,
        easing: o.animateEasing,
        step: function() {

          var data = {
            width: parseFloat( that.element.css( "width" ) ),
            height: parseFloat( that.element.css( "height" ) ),
            top: parseFloat( that.element.css( "top" ) ),
            left: parseFloat( that.element.css( "left" ) )
          };

          if ( pr && pr.length ) {
            $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
          }

          // Propagating resize, and updating values for each animation step
          that._updateCache( data );
          that._propagate( "resize", event );

        }
      }
    );
  }

} );

$.ui.plugin.add( "resizable", "containment", {

  start: function() {
    var element, p, co, ch, cw, width, height,
      that = $( this ).resizable( "instance" ),
      o = that.options,
      el = that.element,
      oc = o.containment,
      ce = ( oc instanceof $ ) ?
        oc.get( 0 ) :
        ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;

    if ( !ce ) {
      return;
    }

    that.containerElement = $( ce );

    if ( /document/.test( oc ) || oc === document ) {
      that.containerOffset = {
        left: 0,
        top: 0
      };
      that.containerPosition = {
        left: 0,
        top: 0
      };

      that.parentData = {
        element: $( document ),
        left: 0,
        top: 0,
        width: $( document ).width(),
        height: $( document ).height() || document.body.parentNode.scrollHeight
      };
    } else {
      element = $( ce );
      p = [];
      $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
        p[ i ] = that._num( element.css( "padding" + name ) );
      } );

      that.containerOffset = element.offset();
      that.containerPosition = element.position();
      that.containerSize = {
        height: ( element.innerHeight() - p[ 3 ] ),
        width: ( element.innerWidth() - p[ 1 ] )
      };

      co = that.containerOffset;
      ch = that.containerSize.height;
      cw = that.containerSize.width;
      width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
      height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;

      that.parentData = {
        element: ce,
        left: co.left,
        top: co.top,
        width: width,
        height: height
      };
    }
  },

  resize: function( event ) {
    var woset, hoset, isParent, isOffsetRelative,
      that = $( this ).resizable( "instance" ),
      o = that.options,
      co = that.containerOffset,
      cp = that.position,
      pRatio = that._aspectRatio || event.shiftKey,
      cop = {
        top: 0,
        left: 0
      },
      ce = that.containerElement,
      continueResize = true;

    if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
      cop = co;
    }

    if ( cp.left < ( that._helper ? co.left : 0 ) ) {
      that.size.width = that.size.width +
        ( that._helper ?
          ( that.position.left - co.left ) :
          ( that.position.left - cop.left ) );

      if ( pRatio ) {
        that.size.height = that.size.width / that.aspectRatio;
        continueResize = false;
      }
      that.position.left = o.helper ? co.left : 0;
    }

    if ( cp.top < ( that._helper ? co.top : 0 ) ) {
      that.size.height = that.size.height +
        ( that._helper ?
          ( that.position.top - co.top ) :
          that.position.top );

      if ( pRatio ) {
        that.size.width = that.size.height * that.aspectRatio;
        continueResize = false;
      }
      that.position.top = that._helper ? co.top : 0;
    }

    isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
    isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );

    if ( isParent && isOffsetRelative ) {
      that.offset.left = that.parentData.left + that.position.left;
      that.offset.top = that.parentData.top + that.position.top;
    } else {
      that.offset.left = that.element.offset().left;
      that.offset.top = that.element.offset().top;
    }

    woset = Math.abs( that.sizeDiff.width +
      ( that._helper ?
        that.offset.left - cop.left :
        ( that.offset.left - co.left ) ) );

    hoset = Math.abs( that.sizeDiff.height +
      ( that._helper ?
        that.offset.top - cop.top :
        ( that.offset.top - co.top ) ) );

    if ( woset + that.size.width >= that.parentData.width ) {
      that.size.width = that.parentData.width - woset;
      if ( pRatio ) {
        that.size.height = that.size.width / that.aspectRatio;
        continueResize = false;
      }
    }

    if ( hoset + that.size.height >= that.parentData.height ) {
      that.size.height = that.parentData.height - hoset;
      if ( pRatio ) {
        that.size.width = that.size.height * that.aspectRatio;
        continueResize = false;
      }
    }

    if ( !continueResize ) {
      that.position.left = that.prevPosition.left;
      that.position.top = that.prevPosition.top;
      that.size.width = that.prevSize.width;
      that.size.height = that.prevSize.height;
    }
  },

  stop: function() {
    var that = $( this ).resizable( "instance" ),
      o = that.options,
      co = that.containerOffset,
      cop = that.containerPosition,
      ce = that.containerElement,
      helper = $( that.helper ),
      ho = helper.offset(),
      w = helper.outerWidth() - that.sizeDiff.width,
      h = helper.outerHeight() - that.sizeDiff.height;

    if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
      $( this ).css( {
        left: ho.left - cop.left - co.left,
        width: w,
        height: h
      } );
    }

    if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
      $( this ).css( {
        left: ho.left - cop.left - co.left,
        width: w,
        height: h
      } );
    }
  }
} );

$.ui.plugin.add( "resizable", "alsoResize", {

  start: function() {
    var that = $( this ).resizable( "instance" ),
      o = that.options;

    $( o.alsoResize ).each( function() {
      var el = $( this );
      el.data( "ui-resizable-alsoresize", {
        width: parseFloat( el.width() ), height: parseFloat( el.height() ),
        left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
      } );
    } );
  },

  resize: function( event, ui ) {
    var that = $( this ).resizable( "instance" ),
      o = that.options,
      os = that.originalSize,
      op = that.originalPosition,
      delta = {
        height: ( that.size.height - os.height ) || 0,
        width: ( that.size.width - os.width ) || 0,
        top: ( that.position.top - op.top ) || 0,
        left: ( that.position.left - op.left ) || 0
      };

      $( o.alsoResize ).each( function() {
        var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
          css = el.parents( ui.originalElement[ 0 ] ).length ?
              [ "width", "height" ] :
              [ "width", "height", "top", "left" ];

        $.each( css, function( i, prop ) {
          var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
          if ( sum && sum >= 0 ) {
            style[ prop ] = sum || null;
          }
        } );

        el.css( style );
      } );
  },

  stop: function() {
    $( this ).removeData( "ui-resizable-alsoresize" );
  }
} );

$.ui.plugin.add( "resizable", "ghost", {

  start: function() {

    var that = $( this ).resizable( "instance" ), cs = that.size;

    that.ghost = that.originalElement.clone();
    that.ghost.css( {
      opacity: 0.25,
      display: "block",
      position: "relative",
      height: cs.height,
      width: cs.width,
      margin: 0,
      left: 0,
      top: 0
    } );

    that._addClass( that.ghost, "ui-resizable-ghost" );

    // DEPRECATED
    // TODO: remove after 1.12
    if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {

      // Ghost option
      that.ghost.addClass( this.options.ghost );
    }

    that.ghost.appendTo( that.helper );

  },

  resize: function() {
    var that = $( this ).resizable( "instance" );
    if ( that.ghost ) {
      that.ghost.css( {
        position: "relative",
        height: that.size.height,
        width: that.size.width
      } );
    }
  },

  stop: function() {
    var that = $( this ).resizable( "instance" );
    if ( that.ghost && that.helper ) {
      that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
    }
  }

} );

$.ui.plugin.add( "resizable", "grid", {

  resize: function() {
    var outerDimensions,
      that = $( this ).resizable( "instance" ),
      o = that.options,
      cs = that.size,
      os = that.originalSize,
      op = that.originalPosition,
      a = that.axis,
      grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
      gridX = ( grid[ 0 ] || 1 ),
      gridY = ( grid[ 1 ] || 1 ),
      ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
      oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
      newWidth = os.width + ox,
      newHeight = os.height + oy,
      isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
      isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
      isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
      isMinHeight = o.minHeight && ( o.minHeight > newHeight );

    o.grid = grid;

    if ( isMinWidth ) {
      newWidth += gridX;
    }
    if ( isMinHeight ) {
      newHeight += gridY;
    }
    if ( isMaxWidth ) {
      newWidth -= gridX;
    }
    if ( isMaxHeight ) {
      newHeight -= gridY;
    }

    if ( /^(se|s|e)$/.test( a ) ) {
      that.size.width = newWidth;
      that.size.height = newHeight;
    } else if ( /^(ne)$/.test( a ) ) {
      that.size.width = newWidth;
      that.size.height = newHeight;
      that.position.top = op.top - oy;
    } else if ( /^(sw)$/.test( a ) ) {
      that.size.width = newWidth;
      that.size.height = newHeight;
      that.position.left = op.left - ox;
    } else {
      if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
        outerDimensions = that._getPaddingPlusBorderDimensions( this );
      }

      if ( newHeight - gridY > 0 ) {
        that.size.height = newHeight;
        that.position.top = op.top - oy;
      } else {
        newHeight = gridY - outerDimensions.height;
        that.size.height = newHeight;
        that.position.top = op.top + os.height - newHeight;
      }
      if ( newWidth - gridX > 0 ) {
        that.size.width = newWidth;
        that.position.left = op.left - ox;
      } else {
        newWidth = gridX - outerDimensions.width;
        that.size.width = newWidth;
        that.position.left = op.left + os.width - newWidth;
      }
    }
  }

} );

var widgetsResizable = $.ui.resizable;




}));
