3 Commits 518f1439b1 ... 65302d0cba

Author SHA1 Message Date
  柳建 65302d0cba 添加遗漏文件 9 months ago
  柳建 815fffcf2b Merge remote-tracking branch 'origin/master' 9 months ago
  柳建 9b30460f56 add 9 months ago
100 changed files with 30286 additions and 0 deletions
  1. 40 0
      public/assets/libs/Sortable/.bower.json
  2. 33 0
      public/assets/libs/Sortable/.circleci/config.yml
  3. 15 0
      public/assets/libs/Sortable/.editorconfig
  4. 6 0
      public/assets/libs/Sortable/.gitignore
  5. 25 0
      public/assets/libs/Sortable/.jshintrc
  6. 7 0
      public/assets/libs/Sortable/.testcaferc.json
  7. 26 0
      public/assets/libs/Sortable/CONTRIBUTING.md
  8. 24 0
      public/assets/libs/Sortable/ISSUE_TEMPLATE.md
  9. 21 0
      public/assets/libs/Sortable/LICENSE
  10. 813 0
      public/assets/libs/Sortable/README.md
  11. 3709 0
      public/assets/libs/Sortable/Sortable.js
  12. 1 0
      public/assets/libs/Sortable/Sortable.min.js
  13. 27 0
      public/assets/libs/Sortable/babel.config.js
  14. 30 0
      public/assets/libs/Sortable/bower.json
  15. 8 0
      public/assets/libs/Sortable/entry/entry-complete.js
  16. 19 0
      public/assets/libs/Sortable/entry/entry-core.js
  17. 19 0
      public/assets/libs/Sortable/entry/entry-defaults.js
  18. 459 0
      public/assets/libs/Sortable/index.html
  19. 3701 0
      public/assets/libs/Sortable/modular/sortable.complete.esm.js
  20. 3698 0
      public/assets/libs/Sortable/modular/sortable.core.esm.js
  21. 3699 0
      public/assets/libs/Sortable/modular/sortable.esm.js
  22. 5704 0
      public/assets/libs/Sortable/package-lock.json
  23. 56 0
      public/assets/libs/Sortable/package.json
  24. 270 0
      public/assets/libs/Sortable/plugins/AutoScroll/AutoScroll.js
  25. 80 0
      public/assets/libs/Sortable/plugins/AutoScroll/README.md
  26. 1 0
      public/assets/libs/Sortable/plugins/AutoScroll/index.js
  27. 617 0
      public/assets/libs/Sortable/plugins/MultiDrag/MultiDrag.js
  28. 96 0
      public/assets/libs/Sortable/plugins/MultiDrag/README.md
  29. 1 0
      public/assets/libs/Sortable/plugins/MultiDrag/index.js
  30. 79 0
      public/assets/libs/Sortable/plugins/OnSpill/OnSpill.js
  31. 60 0
      public/assets/libs/Sortable/plugins/OnSpill/README.md
  32. 1 0
      public/assets/libs/Sortable/plugins/OnSpill/index.js
  33. 178 0
      public/assets/libs/Sortable/plugins/README.md
  34. 55 0
      public/assets/libs/Sortable/plugins/Swap/README.md
  35. 90 0
      public/assets/libs/Sortable/plugins/Swap/Swap.js
  36. 1 0
      public/assets/libs/Sortable/plugins/Swap/index.js
  37. 8 0
      public/assets/libs/Sortable/scripts/banner.js
  38. 17 0
      public/assets/libs/Sortable/scripts/build.js
  39. 28 0
      public/assets/libs/Sortable/scripts/esm-build.js
  40. 11 0
      public/assets/libs/Sortable/scripts/minify.js
  41. 30 0
      public/assets/libs/Sortable/scripts/test-compat.js
  42. 21 0
      public/assets/libs/Sortable/scripts/test.js
  43. 15 0
      public/assets/libs/Sortable/scripts/umd-build.js
  44. 175 0
      public/assets/libs/Sortable/src/Animation.js
  45. 12 0
      public/assets/libs/Sortable/src/BrowserInfo.js
  46. 57 0
      public/assets/libs/Sortable/src/EventDispatcher.js
  47. 87 0
      public/assets/libs/Sortable/src/PluginManager.js
  48. 1966 0
      public/assets/libs/Sortable/src/Sortable.js
  49. 556 0
      public/assets/libs/Sortable/src/utils.js
  50. 222 0
      public/assets/libs/Sortable/st/app.js
  51. 32 0
      public/assets/libs/Sortable/st/iframe/frame.html
  52. 49 0
      public/assets/libs/Sortable/st/iframe/index.html
  53. BIN
      public/assets/libs/Sortable/st/logo.png
  54. BIN
      public/assets/libs/Sortable/st/og-image.png
  55. 1 0
      public/assets/libs/Sortable/st/prettify/prettify.css
  56. 46 0
      public/assets/libs/Sortable/st/prettify/prettify.js
  57. 64 0
      public/assets/libs/Sortable/st/prettify/run_prettify.js
  58. 0 0
      public/assets/libs/Sortable/st/saucelabs.svg
  59. 254 0
      public/assets/libs/Sortable/st/theme.css
  60. 14 0
      public/assets/libs/art-template/.bower.json
  61. 4 0
      public/assets/libs/art-template/.gitignore
  62. 3 0
      public/assets/libs/art-template/.npmignore
  63. 99 0
      public/assets/libs/art-template/Gruntfile.js
  64. 303 0
      public/assets/libs/art-template/README.md
  65. 34 0
      public/assets/libs/art-template/demo/basic.html
  66. 27 0
      public/assets/libs/art-template/demo/compile.html
  67. 24 0
      public/assets/libs/art-template/demo/debug-syntax.html
  68. 29 0
      public/assets/libs/art-template/demo/debug.html
  69. 87 0
      public/assets/libs/art-template/demo/helper.html
  70. 32 0
      public/assets/libs/art-template/demo/include.html
  71. 21 0
      public/assets/libs/art-template/demo/index.html
  72. 25 0
      public/assets/libs/art-template/demo/no-escape.html
  73. 48 0
      public/assets/libs/art-template/demo/node-template-express.js
  74. 35 0
      public/assets/libs/art-template/demo/node-template.js
  75. 1 0
      public/assets/libs/art-template/demo/node-template/copyright.html
  76. 12 0
      public/assets/libs/art-template/demo/node-template/index.html
  77. 6 0
      public/assets/libs/art-template/demo/node-template/public/footer.html
  78. 11 0
      public/assets/libs/art-template/demo/node-template/public/header.html
  79. 7 0
      public/assets/libs/art-template/demo/node-template/public/logo.html
  80. 29 0
      public/assets/libs/art-template/demo/print.html
  81. 34 0
      public/assets/libs/art-template/demo/template-native/basic.html
  82. 27 0
      public/assets/libs/art-template/demo/template-native/compile.html
  83. 35 0
      public/assets/libs/art-template/demo/template-native/debug-syntax.html
  84. 35 0
      public/assets/libs/art-template/demo/template-native/debug.html
  85. 76 0
      public/assets/libs/art-template/demo/template-native/helper.html
  86. 32 0
      public/assets/libs/art-template/demo/template-native/include.html
  87. 22 0
      public/assets/libs/art-template/demo/template-native/index.html
  88. 25 0
      public/assets/libs/art-template/demo/template-native/no-escape.html
  89. 30 0
      public/assets/libs/art-template/demo/template-native/print.html
  90. 42 0
      public/assets/libs/art-template/demo/template-native/tag.html
  91. 739 0
      public/assets/libs/art-template/dist/template-debug.js
  92. 602 0
      public/assets/libs/art-template/dist/template-native-debug.js
  93. 1 0
      public/assets/libs/art-template/dist/template-native.js
  94. 1 0
      public/assets/libs/art-template/dist/template.js
  95. 73 0
      public/assets/libs/art-template/doc/syntax-native.md
  96. 90 0
      public/assets/libs/art-template/doc/syntax-simple.md
  97. 18 0
      public/assets/libs/art-template/loader/index.js
  98. 14 0
      public/assets/libs/art-template/loader/package.json
  99. 129 0
      public/assets/libs/art-template/loader/runtime.js
  100. 90 0
      public/assets/libs/art-template/node/_node.js

+ 40 - 0
public/assets/libs/Sortable/.bower.json

@@ -0,0 +1,40 @@
+{
+  "name": "Sortable",
+  "main": [
+    "Sortable.js"
+  ],
+  "homepage": "http://SortableJS.github.io/Sortable/",
+  "authors": [
+    "RubaXa <ibnRubaXa@gmail.com>",
+    "owenm <owen23355@gmail.com>"
+  ],
+  "description": "JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.",
+  "keywords": [
+    "sortable",
+    "reorder",
+    "list",
+    "html5",
+    "drag",
+    "and",
+    "drop",
+    "dnd",
+    "web-components"
+  ],
+  "license": "MIT",
+  "ignore": [
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "version": "1.10.2",
+  "_release": "1.10.2",
+  "_resolution": {
+    "type": "version",
+    "tag": "1.10.2",
+    "commit": "2addddd67387b6e4b6b5e51806eb698f0a3eee88"
+  },
+  "_source": "https://github.com/RubaXa/Sortable.git",
+  "_target": "~1.10.0",
+  "_originalSource": "Sortable"
+}

+ 33 - 0
public/assets/libs/Sortable/.circleci/config.yml

@@ -0,0 +1,33 @@
+version: 2.0
+jobs:
+  build:
+    docker:
+      - image: circleci/node:10.16-browsers
+    steps:
+      - checkout
+
+      - restore_cache:
+          keys:
+          - v1-dependencies-{{ checksum "package.json" }}
+          - v1-dependencies-
+
+      - run: npm install
+
+      - save_cache:
+          paths:
+            - node_modules
+          key: v1-dependencies-{{ checksum "package.json" }}
+
+      - run: npm run build:umd
+
+      - run:
+          name: Compatibility Test
+          command: |
+            if [ -z "$CIRCLE_PR_NUMBER" ];
+            then
+              npm run test:compat
+            fi
+      - run: npm run test
+
+      - store_test_results:
+          path: /tmp/test-results

+ 15 - 0
public/assets/libs/Sortable/.editorconfig

@@ -0,0 +1,15 @@
+# editorconfig.org
+root = true
+
+[*]
+indent_style = tab
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.yml]
+indent_style = space

+ 6 - 0
public/assets/libs/Sortable/.gitignore

@@ -0,0 +1,6 @@
+node_modules
+mock.png
+.*.sw*
+.build*
+jquery.fn.*
+.idea/

+ 25 - 0
public/assets/libs/Sortable/.jshintrc

@@ -0,0 +1,25 @@
+{
+	"strict": false,
+	"newcap": false,
+	"node": true,
+	"expr": true,
+	"supernew": true,
+	"laxbreak": true,
+	"esversion": 9,
+	"white": true,
+	"globals": {
+		"define": true,
+		"test": true,
+		"expect": true,
+		"module": true,
+		"asyncTest": true,
+		"start": true,
+		"ok": true,
+		"equal": true,
+		"notEqual": true,
+		"deepEqual": true,
+		"window": true,
+		"document": true,
+		"performance": true
+	}
+}

+ 7 - 0
public/assets/libs/Sortable/.testcaferc.json

@@ -0,0 +1,7 @@
+{
+	"speed": 0.4,
+	"reporter": {
+		"name": "xunit",
+		"output": "/tmp/test-results/res.xml"
+	}
+}

+ 26 - 0
public/assets/libs/Sortable/CONTRIBUTING.md

@@ -0,0 +1,26 @@
+# Contribution Guidelines
+
+### Issue
+
+ 1. Try [master](https://github.com/SortableJS/Sortable/tree/master/)-branch, perhaps the problem has been solved;
+ 2. [Use the search](https://github.com/SortableJS/Sortable/search?type=Issues&q=problem), maybe already have an answer;
+ 3. If not found, create example on [jsbin.com (draft)](https://jsbin.com/kamiwez/edit?html,js,output) and describe the problem.
+
+---
+
+### Pull Request
+
+ 1. Only request to merge with the [master](https://github.com/SortableJS/Sortable/tree/master/)-branch.
+ 2. Only modify source files, **do not commit the resulting build**
+
+### Setup
+
+ 1. Fork the repo on [github](https://github.com)
+ 2. Clone locally
+ 3. Run `npm i` in the local repo
+
+### Building
+
+ - For development, build the `./Sortable.js` file using the command `npm run build:umd:watch`
+ - To build everything and minify it, run `npm run build`
+ - Do not commit the resulting builds in any pull request – they will be generated at release

+ 24 - 0
public/assets/libs/Sortable/ISSUE_TEMPLATE.md

@@ -0,0 +1,24 @@
+#### Problem:
+
+
+
+#### JSBin/JSFiddle demonstrating the problem:
+
+
+---
+Before you create an issue, check it:
+
+ 1. Try [master](https://github.com/SortableJS/Sortable/tree/master/)-branch, perhaps the problem has been solved;
+ 2. [Use the search](https://github.com/SortableJS/Sortable/search?q=problem), maybe we already have an answer;
+ 3. If not found, create an example on [jsbin.com (draft)](http://jsbin.com/vojixek/edit?html,js,output) and describe the problem.
+
+Bindings:
+ - Angular
+   - 2.0+: https://github.com/SortableJS/angular-sortablejs/issues
+   - legacy: https://github.com/SortableJS/angular-legacy-sortablejs/issues
+ - React
+   - ES2015+: https://github.com/SortableJS/react-sortablejs/issues
+   - mixin: https://github.com/SortableJS/react-mixin-sortablejs/issues
+ - Polymer: https://github.com/SortableJS/polymer-sortablejs/issues
+ - Knockout: https://github.com/SortableJS/knockout-sortablejs/issues
+ - Meteor: https://github.com/SortableJS/meteor-sortablejs/issues

+ 21 - 0
public/assets/libs/Sortable/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 All contributors to Sortable
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 813 - 0
public/assets/libs/Sortable/README.md

@@ -0,0 +1,813 @@
+# Sortable &nbsp; [![Financial Contributors on Open Collective](https://opencollective.com/Sortable/all/badge.svg?label=financial+contributors)](https://opencollective.com/Sortable) [![CircleCI](https://circleci.com/gh/SortableJS/Sortable.svg?style=svg)](https://circleci.com/gh/SortableJS/Sortable) [![DeepScan grade](https://deepscan.io/api/teams/3901/projects/5666/branches/43977/badge/grade.svg)](https://deepscan.io/dashboard#view=project&tid=3901&pid=5666&bid=43977) [![](https://data.jsdelivr.com/v1/package/npm/sortablejs/badge)](https://www.jsdelivr.com/package/npm/sortablejs) [![npm](https://img.shields.io/npm/v/sortablejs.svg)](https://www.npmjs.com/package/sortablejs)
+
+Sortable is a JavaScript library for reorderable drag-and-drop lists.
+
+Demo: http://sortablejs.github.io/Sortable/
+
+[<img width="250px" src="https://raw.githubusercontent.com/SortableJS/Sortable/HEAD/st/saucelabs.svg?sanitize=true">](https://saucelabs.com/)
+
+## Features
+
+ * Supports touch devices and [modern](http://caniuse.com/#search=drag) browsers (including IE9)
+ * Can drag from one list to another or within the same list
+ * CSS animation when moving items
+ * Supports drag handles *and selectable text* (better than voidberg's html5sortable)
+ * Smart auto-scrolling
+ * Advanced swap detection
+ * Smooth animations
+ * [Multi-drag](https://github.com/SortableJS/Sortable/tree/master/plugins/MultiDrag) support
+ * Support for CSS transforms
+ * Built using native HTML5 drag and drop API
+ * Supports
+   * [Meteor](https://github.com/SortableJS/meteor-sortablejs)
+   * Angular
+     * [2.0+](https://github.com/SortableJS/angular-sortablejs)
+     * [1.&ast;](https://github.com/SortableJS/angular-legacy-sortablejs)
+   * React
+     * [ES2015+](https://github.com/SortableJS/react-sortablejs)
+     * [Mixin](https://github.com/SortableJS/react-mixin-sortablejs)
+   * [Knockout](https://github.com/SortableJS/knockout-sortablejs)
+   * [Polymer](https://github.com/SortableJS/polymer-sortablejs)
+   * [Vue](https://github.com/SortableJS/Vue.Draggable)
+   * [Ember](https://github.com/SortableJS/ember-sortablejs)
+ * Supports any CSS library, e.g. [Bootstrap](#bs)
+ * Simple API
+ * Support for [plugins](#plugins)
+ * [CDN](#cdn)
+ * No jQuery required (but there is [support](https://github.com/SortableJS/jquery-sortablejs))
+ * Typescript definitions at `@types/sortablejs`
+
+
+<br/>
+
+
+### Articles
+
+ * [Dragging Multiple Items in Sortable](https://github.com/SortableJS/Sortable/wiki/Dragging-Multiple-Items-in-Sortable) (April 26, 2019)
+ * [Swap Thresholds and Direction](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction) (December 2, 2018)
+ * [Sortable v1.0 — New capabilities](https://github.com/SortableJS/Sortable/wiki/Sortable-v1.0-—-New-capabilities/) (December 22, 2014)
+ * [Sorting with the help of HTML5 Drag'n'Drop API](https://github.com/SortableJS/Sortable/wiki/Sorting-with-the-help-of-HTML5-Drag'n'Drop-API/) (December 23, 2013)
+
+<br/>
+
+### Getting Started
+
+Install with NPM:
+```bash
+$ npm install sortablejs --save
+```
+
+Install with Bower:
+```bash
+$ bower install --save sortablejs
+```
+
+Import into your project:
+```js
+// Default SortableJS
+import Sortable from 'sortablejs';
+
+// Core SortableJS (without default plugins)
+import Sortable from 'sortablejs/modular/sortable.core.esm.js';
+
+// Complete SortableJS (with all plugins)
+import Sortable from 'sortablejs/modular/sortable.complete.esm.js';
+```
+
+Cherrypick plugins:
+```js
+// Cherrypick extra plugins
+import Sortable, { MultiDrag, Swap } from 'sortablejs';
+
+Sortable.mount(new MultiDrag(), new Swap());
+
+
+// Cherrypick default plugins
+import Sortable, { AutoScroll } from 'sortablejs/modular/sortable.core.esm.js';
+
+Sortable.mount(new AutoScroll());
+```
+
+
+---
+
+
+### Usage
+```html
+<ul id="items">
+	<li>item 1</li>
+	<li>item 2</li>
+	<li>item 3</li>
+</ul>
+```
+
+```js
+var el = document.getElementById('items');
+var sortable = Sortable.create(el);
+```
+
+You can use any element for the list and its elements, not just `ul`/`li`. Here is an [example with `div`s](https://jsbin.com/visimub/edit?html,js,output).
+
+
+---
+
+
+### Options
+```js
+var sortable = new Sortable(el, {
+	group: "name",  // or { name: "...", pull: [true, false, 'clone', array], put: [true, false, array] }
+	sort: true,  // sorting inside list
+	delay: 0, // time in milliseconds to define when the sorting should start
+	delayOnTouchOnly: false, // only delay if user is using touch
+	touchStartThreshold: 0, // px, how many pixels the point should move before cancelling a delayed drag event
+	disabled: false, // Disables the sortable if set to true.
+	store: null,  // @see Store
+	animation: 150,  // ms, animation speed moving items when sorting, `0` — without animation
+	easing: "cubic-bezier(1, 0, 0, 1)", // Easing for animation. Defaults to null. See https://easings.net/ for examples.
+	handle: ".my-handle",  // Drag handle selector within list items
+	filter: ".ignore-elements",  // Selectors that do not lead to dragging (String or Function)
+	preventOnFilter: true, // Call `event.preventDefault()` when triggered `filter`
+	draggable: ".item",  // Specifies which items inside the element should be draggable
+
+	dataIdAttr: 'data-id',
+
+	ghostClass: "sortable-ghost",  // Class name for the drop placeholder
+	chosenClass: "sortable-chosen",  // Class name for the chosen item
+	dragClass: "sortable-drag",  // Class name for the dragging item
+
+	swapThreshold: 1, // Threshold of the swap zone
+	invertSwap: false, // Will always use inverted swap zone if set to true
+	invertedSwapThreshold: 1, // Threshold of the inverted swap zone (will be set to swapThreshold value by default)
+	direction: 'horizontal', // Direction of Sortable (will be detected automatically if not given)
+
+	forceFallback: false,  // ignore the HTML5 DnD behaviour and force the fallback to kick in
+
+	fallbackClass: "sortable-fallback",  // Class name for the cloned DOM Element when using forceFallback
+	fallbackOnBody: false,  // Appends the cloned DOM Element into the Document's Body
+	fallbackTolerance: 0, // Specify in pixels how far the mouse should move before it's considered as a drag.
+
+	dragoverBubble: false,
+	removeCloneOnHide: true, // Remove the clone element when it is not showing, rather than just hiding it
+	emptyInsertThreshold: 5, // px, distance mouse must be from empty sortable to insert drag element into it
+
+
+	setData: function (/** DataTransfer */dataTransfer, /** HTMLElement*/dragEl) {
+		dataTransfer.setData('Text', dragEl.textContent); // `dataTransfer` object of HTML5 DragEvent
+	},
+
+	// Element is chosen
+	onChoose: function (/**Event*/evt) {
+		evt.oldIndex;  // element index within parent
+	},
+
+	// Element is unchosen
+	onUnchoose: function(/**Event*/evt) {
+		// same properties as onEnd
+	},
+
+	// Element dragging started
+	onStart: function (/**Event*/evt) {
+		evt.oldIndex;  // element index within parent
+	},
+
+	// Element dragging ended
+	onEnd: function (/**Event*/evt) {
+		var itemEl = evt.item;  // dragged HTMLElement
+		evt.to;    // target list
+		evt.from;  // previous list
+		evt.oldIndex;  // element's old index within old parent
+		evt.newIndex;  // element's new index within new parent
+		evt.oldDraggableIndex; // element's old index within old parent, only counting draggable elements
+		evt.newDraggableIndex; // element's new index within new parent, only counting draggable elements
+		evt.clone // the clone element
+		evt.pullMode;  // when item is in another sortable: `"clone"` if cloning, `true` if moving
+	},
+
+	// Element is dropped into the list from another list
+	onAdd: function (/**Event*/evt) {
+		// same properties as onEnd
+	},
+
+	// Changed sorting within list
+	onUpdate: function (/**Event*/evt) {
+		// same properties as onEnd
+	},
+
+	// Called by any change to the list (add / update / remove)
+	onSort: function (/**Event*/evt) {
+		// same properties as onEnd
+	},
+
+	// Element is removed from the list into another list
+	onRemove: function (/**Event*/evt) {
+		// same properties as onEnd
+	},
+
+	// Attempt to drag a filtered element
+	onFilter: function (/**Event*/evt) {
+		var itemEl = evt.item;  // HTMLElement receiving the `mousedown|tapstart` event.
+	},
+
+	// Event when you move an item in the list or between lists
+	onMove: function (/**Event*/evt, /**Event*/originalEvent) {
+		// Example: https://jsbin.com/nawahef/edit?js,output
+		evt.dragged; // dragged HTMLElement
+		evt.draggedRect; // DOMRect {left, top, right, bottom}
+		evt.related; // HTMLElement on which have guided
+		evt.relatedRect; // DOMRect
+		evt.willInsertAfter; // Boolean that is true if Sortable will insert drag element after target by default
+		originalEvent.clientY; // mouse position
+		// return false; — for cancel
+		// return -1; — insert before target
+		// return 1; — insert after target
+	},
+
+	// Called when creating a clone of element
+	onClone: function (/**Event*/evt) {
+		var origEl = evt.item;
+		var cloneEl = evt.clone;
+	},
+
+	// Called when dragging element changes position
+	onChange: function(/**Event*/evt) {
+		evt.newIndex // most likely why this event is used is to get the dragging element's current index
+		// same properties as onEnd
+	}
+});
+```
+
+
+---
+
+
+#### `group` option
+To drag elements from one list into another, both lists must have the same `group` value.
+You can also define whether lists can give away, give and keep a copy (`clone`), and receive elements.
+
+ * name: `String` — group name
+ * pull: `true|false|["foo", "bar"]|'clone'|function` — ability to move from the list. `clone` — copy the item, rather than move. Or an array of group names which the elements may be put in. Defaults to `true`.
+ * put: `true|false|["baz", "qux"]|function` — whether elements can be added from other lists, or an array of group names from which elements can be added.
+ * revertClone: `boolean` — revert cloned element to initial position after moving to a another list.
+
+
+Demo:
+ - https://jsbin.com/hijetos/edit?js,output
+ - https://jsbin.com/nacoyah/edit?js,output — use of complex logic in the `pull` and` put`
+ - https://jsbin.com/bifuyab/edit?js,output — use `revertClone: true`
+
+
+---
+
+
+#### `sort` option
+Allow sorting inside list.
+
+Demo: https://jsbin.com/jayedig/edit?js,output
+
+
+---
+
+
+#### `delay` option
+Time in milliseconds to define when the sorting should start.
+Unfortunately, due to browser restrictions, delaying is not possible on IE or Edge with native drag & drop.
+
+Demo: https://jsbin.com/zosiwah/edit?js,output
+
+
+---
+
+
+#### `delayOnTouchOnly` option
+Whether or not the delay should be applied only if the user is using touch (eg. on a mobile device). No delay will be applied in any other case. Defaults to `false`.
+
+
+---
+
+
+#### `swapThreshold` option
+Percentage of the target that the swap zone will take up, as a float between `0` and `1`.
+
+[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#swap-threshold)
+
+Demo: http://sortablejs.github.io/Sortable#thresholds
+
+
+---
+
+
+#### `invertSwap` option
+Set to `true` to set the swap zone to the sides of the target, for the effect of sorting "in between" items.
+
+[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#forcing-inverted-swap-zone)
+
+Demo: http://sortablejs.github.io/Sortable#thresholds
+
+
+---
+
+
+#### `invertedSwapThreshold` option
+Percentage of the target that the inverted swap zone will take up, as a float between `0` and `1`. If not given, will default to `swapThreshold`.
+
+[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#dealing-with-swap-glitching)
+
+
+---
+
+
+#### `direction` option
+Direction that the Sortable should sort in. Can be set to `'vertical'`, `'horizontal'`, or a function, which will be called whenever a target is dragged over. Must return `'vertical'` or `'horizontal'`.
+
+[Read more](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#direction)
+
+
+Example of direction detection for vertical list that includes full column and half column elements:
+
+```js
+Sortable.create(el, {
+	direction: function(evt, target, dragEl) {
+		if (target !== null && target.className.includes('half-column') && dragEl.className.includes('half-column')) {
+			return 'horizontal';
+		}
+		return 'vertical';
+	}
+});
+```
+
+
+---
+
+
+#### `touchStartThreshold` option
+This option is similar to `fallbackTolerance` option.
+
+When the `delay` option is set, some phones with very sensitive touch displays like the Samsung Galaxy S8 will fire
+unwanted touchmove events even when your finger is not moving, resulting in the sort not triggering.
+
+This option sets the minimum pointer movement that must occur before the delayed sorting is cancelled.
+
+Values between 3 to 5 are good.
+
+
+---
+
+
+#### `disabled` options
+Disables the sortable if set to `true`.
+
+Demo: https://jsbin.com/sewokud/edit?js,output
+
+```js
+var sortable = Sortable.create(list);
+
+document.getElementById("switcher").onclick = function () {
+	var state = sortable.option("disabled"); // get
+
+	sortable.option("disabled", !state); // set
+};
+```
+
+
+---
+
+
+#### `handle` option
+To make list items draggable, Sortable disables text selection by the user.
+That's not always desirable. To allow text selection, define a drag handler,
+which is an area of every list element that allows it to be dragged around.
+
+Demo: https://jsbin.com/numakuh/edit?html,js,output
+
+```js
+Sortable.create(el, {
+	handle: ".my-handle"
+});
+```
+
+```html
+<ul>
+	<li><span class="my-handle">::</span> list item text one
+	<li><span class="my-handle">::</span> list item text two
+</ul>
+```
+
+```css
+.my-handle {
+	cursor: move;
+	cursor: -webkit-grabbing;
+}
+```
+
+
+---
+
+
+#### `filter` option
+
+
+```js
+Sortable.create(list, {
+	filter: ".js-remove, .js-edit",
+	onFilter: function (evt) {
+		var item = evt.item,
+			ctrl = evt.target;
+
+		if (Sortable.utils.is(ctrl, ".js-remove")) {  // Click on remove button
+			item.parentNode.removeChild(item); // remove sortable item
+		}
+		else if (Sortable.utils.is(ctrl, ".js-edit")) {  // Click on edit link
+			// ...
+		}
+	}
+})
+```
+
+
+---
+
+
+#### `ghostClass` option
+Class name for the drop placeholder (default `sortable-ghost`).
+
+Demo: https://jsbin.com/henuyiw/edit?css,js,output
+
+```css
+.ghost {
+  opacity: 0.4;
+}
+```
+
+```js
+Sortable.create(list, {
+  ghostClass: "ghost"
+});
+```
+
+
+---
+
+
+#### `chosenClass` option
+Class name for the chosen item  (default `sortable-chosen`).
+
+Demo: https://jsbin.com/hoqufox/edit?css,js,output
+
+```css
+.chosen {
+  color: #fff;
+  background-color: #c00;
+}
+```
+
+```js
+Sortable.create(list, {
+  delay: 500,
+  chosenClass: "chosen"
+});
+```
+
+
+---
+
+
+#### `forceFallback` option
+If set to `true`, the Fallback for non HTML5 Browser will be used, even if we are using an HTML5 Browser.
+This gives us the possibility to test the behaviour for older Browsers even in newer Browser, or make the Drag 'n Drop feel more consistent between Desktop , Mobile and old Browsers.
+
+On top of that, the Fallback always generates a copy of that DOM Element and appends the class `fallbackClass` defined in the options. This behaviour controls the look of this 'dragged' Element.
+
+Demo: https://jsbin.com/sibiput/edit?html,css,js,output
+
+
+---
+
+
+#### `fallbackTolerance` option
+Emulates the native drag threshold. Specify in pixels how far the mouse should move before it's considered as a drag.
+Useful if the items are also clickable like in a list of links.
+
+When the user clicks inside a sortable element, it's not uncommon for your hand to move a little between the time you press and the time you release.
+Dragging only starts if you move the pointer past a certain tolerance, so that you don't accidentally start dragging every time you click.
+
+3 to 5 are probably good values.
+
+
+---
+
+
+#### `dragoverBubble` option
+If set to `true`, the dragover event will bubble to parent sortables. Works on both fallback and native dragover event.
+By default, it is false, but Sortable will only stop bubbling the event once the element has been inserted into a parent Sortable, or *can* be inserted into a parent Sortable, but isn't at that specific time (due to animation, etc).
+
+Since 1.8.0, you will probably want to leave this option as false. Before 1.8.0, it may need to be `true` for nested sortables to work.
+
+
+---
+
+
+#### `removeCloneOnHide` option
+If set to `false`, the clone is hidden by having it's CSS `display` property set to `none`.
+By default, this option is `true`, meaning Sortable will remove the cloned element from the DOM when it is supposed to be hidden.
+
+
+---
+
+
+#### `emptyInsertThreshold` option
+The distance (in pixels) the mouse must be from an empty sortable while dragging for the drag element to be inserted into that sortable. Defaults to `5`. Set to `0` to disable this feature.
+
+Demo: https://jsbin.com/becavoj/edit?js,output
+
+
+---
+### Event object ([demo](https://jsbin.com/fogujiv/edit?js,output))
+
+ - to:`HTMLElement` — list, in which moved element
+ - from:`HTMLElement` — previous list
+ - item:`HTMLElement` — dragged element
+ - clone:`HTMLElement`
+ - oldIndex:`Number|undefined` — old index within parent
+ - newIndex:`Number|undefined` — new index within parent
+ - oldDraggableIndex: `Number|undefined` — old index within parent, only counting draggable elements
+ - newDraggableIndex: `Number|undefined` — new index within parent, only counting draggable elements
+ - pullMode:`String|Boolean|undefined` — Pull mode if dragging into another sortable (`"clone"`, `true`, or `false`), otherwise undefined
+
+
+#### `move` event object
+ - to:`HTMLElement`
+ - from:`HTMLElement`
+ - dragged:`HTMLElement`
+ - draggedRect:`DOMRect`
+ - related:`HTMLElement` — element on which have guided
+ - relatedRect:`DOMRect`
+ - willInsertAfter:`Boolean` — `true` if will element be inserted after target (or `false` if before)
+
+
+---
+
+
+### Method
+
+
+##### option(name:`String`[, value:`*`]):`*`
+Get or set the option.
+
+
+
+##### closest(el:`String`[, selector:`HTMLElement`]):`HTMLElement|null`
+For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+
+
+##### toArray():`String[]`
+Serializes the sortable's item `data-id`'s (`dataIdAttr` option) into an array of string.
+
+
+##### sort(order:`String[]`)
+Sorts the elements according to the array.
+
+```js
+var order = sortable.toArray();
+sortable.sort(order.reverse()); // apply
+```
+
+
+##### save()
+Save the current sorting (see [store](#store))
+
+
+##### destroy()
+Removes the sortable functionality completely.
+
+
+---
+
+
+<a name="store"></a>
+### Store
+Saving and restoring of the sort.
+
+```html
+<ul>
+	<li data-id="1">order</li>
+	<li data-id="2">save</li>
+	<li data-id="3">restore</li>
+</ul>
+```
+
+```js
+Sortable.create(el, {
+	group: "localStorage-example",
+	store: {
+		/**
+		 * Get the order of elements. Called once during initialization.
+		 * @param   {Sortable}  sortable
+		 * @returns {Array}
+		 */
+		get: function (sortable) {
+			var order = localStorage.getItem(sortable.options.group.name);
+			return order ? order.split('|') : [];
+		},
+
+		/**
+		 * Save the order of elements. Called onEnd (when the item is dropped).
+		 * @param {Sortable}  sortable
+		 */
+		set: function (sortable) {
+			var order = sortable.toArray();
+			localStorage.setItem(sortable.options.group.name, order.join('|'));
+		}
+	}
+})
+```
+
+
+---
+
+
+<a name="bs"></a>
+### Bootstrap
+Demo: https://jsbin.com/visimub/edit?html,js,output
+
+```html
+<!-- Latest compiled and minified CSS -->
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
+
+
+<!-- Latest Sortable -->
+<script src="http://SortableJS.github.io/Sortable/Sortable.js"></script>
+
+
+<!-- Simple List -->
+<ul id="simpleList" class="list-group">
+	<li class="list-group-item">This is <a href="http://SortableJS.github.io/Sortable/">Sortable</a></li>
+	<li class="list-group-item">It works with Bootstrap...</li>
+	<li class="list-group-item">...out of the box.</li>
+	<li class="list-group-item">It has support for touch devices.</li>
+	<li class="list-group-item">Just drag some elements around.</li>
+</ul>
+
+<script>
+    // Simple list
+    Sortable.create(simpleList, { /* options */ });
+</script>
+```
+
+
+---
+
+
+### Static methods & properties
+
+
+
+##### Sortable.create(el:`HTMLElement`[, options:`Object`]):`Sortable`
+Create new instance.
+
+
+---
+
+
+##### Sortable.active:`Sortable`
+The active Sortable instance.
+
+
+---
+
+
+##### Sortable.dragged:`HTMLElement`
+The element being dragged.
+
+
+---
+
+
+##### Sortable.ghost:`HTMLElement`
+The ghost element.
+
+
+---
+
+
+##### Sortable.clone:`HTMLElement`
+The clone element.
+
+
+---
+
+
+##### Sortable.get(element:`HTMLElement`):`Sortable`
+Get the Sortable instance on an element.
+
+
+---
+
+
+##### Sortable.mount(plugin:`...SortablePlugin|SortablePlugin[]`)
+Mounts a plugin to Sortable.
+
+
+---
+
+
+##### Sortable.utils
+* on(el`:HTMLElement`, event`:String`, fn`:Function`) — attach an event handler function
+* off(el`:HTMLElement`, event`:String`, fn`:Function`) — remove an event handler
+* css(el`:HTMLElement`)`:Object` — get the values of all the CSS properties
+* css(el`:HTMLElement`, prop`:String`)`:Mixed` — get the value of style properties
+* css(el`:HTMLElement`, prop`:String`, value`:String`) — set one CSS properties
+* css(el`:HTMLElement`, props`:Object`) — set more CSS properties
+* find(ctx`:HTMLElement`, tagName`:String`[, iterator`:Function`])`:Array` — get elements by tag name
+* bind(ctx`:Mixed`, fn`:Function`)`:Function` — Takes a function and returns a new one that will always have a particular context
+* is(el`:HTMLElement`, selector`:String`)`:Boolean` — check the current matched set of elements against a selector
+* closest(el`:HTMLElement`, selector`:String`[, ctx`:HTMLElement`])`:HTMLElement|Null` — for each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree
+* clone(el`:HTMLElement`)`:HTMLElement` — create a deep copy of the set of matched elements
+* toggleClass(el`:HTMLElement`, name`:String`, state`:Boolean`) — add or remove one classes from each element
+* detectDirection(el`:HTMLElement`)`:String` — automatically detect the [direction](https://github.com/SortableJS/Sortable/wiki/Swap-Thresholds-and-Direction#direction) of the element as either `'vertical'` or `'horizontal'`
+
+
+---
+
+
+### Plugins
+#### Extra Plugins (included in complete versions)
+ - [MultiDrag](https://github.com/SortableJS/Sortable/tree/master/plugins/MultiDrag)
+ - [Swap](https://github.com/SortableJS/Sortable/tree/master/plugins/Swap)
+
+#### Default Plugins (included in default versions)
+ - [AutoScroll](https://github.com/SortableJS/Sortable/tree/master/plugins/AutoScroll)
+ - [OnSpill](https://github.com/SortableJS/Sortable/tree/master/plugins/OnSpill)
+
+
+---
+
+
+<a name="cdn"></a>
+### CDN
+
+```html
+<!-- jsDelivr :: Sortable :: Latest (https://www.jsdelivr.com/package/npm/sortablejs) -->
+<script src="https://cdn.jsdelivr.net/npm/sortablejs@latest/Sortable.min.js"></script>
+```
+
+
+---
+
+
+### Contributing (Issue/PR)
+
+Please, [read this](CONTRIBUTING.md).
+
+
+---
+
+
+## Contributors
+
+### Code Contributors
+
+This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
+<a href="https://github.com/SortableJS/Sortable/graphs/contributors"><img src="https://opencollective.com/Sortable/contributors.svg?width=890&button=false" /></a>
+
+### Financial Contributors
+
+Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/Sortable/contribute)]
+
+#### Individuals
+
+<a href="https://opencollective.com/Sortable"><img src="https://opencollective.com/Sortable/individuals.svg?width=890"></a>
+
+#### Organizations
+
+Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/Sortable/contribute)]
+
+<a href="https://opencollective.com/Sortable/organization/0/website"><img src="https://opencollective.com/Sortable/organization/0/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/1/website"><img src="https://opencollective.com/Sortable/organization/1/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/2/website"><img src="https://opencollective.com/Sortable/organization/2/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/3/website"><img src="https://opencollective.com/Sortable/organization/3/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/4/website"><img src="https://opencollective.com/Sortable/organization/4/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/5/website"><img src="https://opencollective.com/Sortable/organization/5/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/6/website"><img src="https://opencollective.com/Sortable/organization/6/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/7/website"><img src="https://opencollective.com/Sortable/organization/7/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/8/website"><img src="https://opencollective.com/Sortable/organization/8/avatar.svg"></a>
+<a href="https://opencollective.com/Sortable/organization/9/website"><img src="https://opencollective.com/Sortable/organization/9/avatar.svg"></a>
+
+## MIT LICENSE
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 3709 - 0
public/assets/libs/Sortable/Sortable.js

@@ -0,0 +1,3709 @@
+/**!
+ * Sortable 1.10.2
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @author	owenm    <owen23355@gmail.com>
+ * @license MIT
+ */
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+  typeof define === 'function' && define.amd ? define(factory) :
+  (global = global || self, global.Sortable = factory());
+}(this, function () { 'use strict';
+
+  function _typeof(obj) {
+    if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+      _typeof = function (obj) {
+        return typeof obj;
+      };
+    } else {
+      _typeof = function (obj) {
+        return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+      };
+    }
+
+    return _typeof(obj);
+  }
+
+  function _defineProperty(obj, key, value) {
+    if (key in obj) {
+      Object.defineProperty(obj, key, {
+        value: value,
+        enumerable: true,
+        configurable: true,
+        writable: true
+      });
+    } else {
+      obj[key] = value;
+    }
+
+    return obj;
+  }
+
+  function _extends() {
+    _extends = Object.assign || function (target) {
+      for (var i = 1; i < arguments.length; i++) {
+        var source = arguments[i];
+
+        for (var key in source) {
+          if (Object.prototype.hasOwnProperty.call(source, key)) {
+            target[key] = source[key];
+          }
+        }
+      }
+
+      return target;
+    };
+
+    return _extends.apply(this, arguments);
+  }
+
+  function _objectSpread(target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i] != null ? arguments[i] : {};
+      var ownKeys = Object.keys(source);
+
+      if (typeof Object.getOwnPropertySymbols === 'function') {
+        ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
+          return Object.getOwnPropertyDescriptor(source, sym).enumerable;
+        }));
+      }
+
+      ownKeys.forEach(function (key) {
+        _defineProperty(target, key, source[key]);
+      });
+    }
+
+    return target;
+  }
+
+  function _objectWithoutPropertiesLoose(source, excluded) {
+    if (source == null) return {};
+    var target = {};
+    var sourceKeys = Object.keys(source);
+    var key, i;
+
+    for (i = 0; i < sourceKeys.length; i++) {
+      key = sourceKeys[i];
+      if (excluded.indexOf(key) >= 0) continue;
+      target[key] = source[key];
+    }
+
+    return target;
+  }
+
+  function _objectWithoutProperties(source, excluded) {
+    if (source == null) return {};
+
+    var target = _objectWithoutPropertiesLoose(source, excluded);
+
+    var key, i;
+
+    if (Object.getOwnPropertySymbols) {
+      var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
+
+      for (i = 0; i < sourceSymbolKeys.length; i++) {
+        key = sourceSymbolKeys[i];
+        if (excluded.indexOf(key) >= 0) continue;
+        if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
+        target[key] = source[key];
+      }
+    }
+
+    return target;
+  }
+
+  function _toConsumableArray(arr) {
+    return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
+  }
+
+  function _arrayWithoutHoles(arr) {
+    if (Array.isArray(arr)) {
+      for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
+
+      return arr2;
+    }
+  }
+
+  function _iterableToArray(iter) {
+    if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
+  }
+
+  function _nonIterableSpread() {
+    throw new TypeError("Invalid attempt to spread non-iterable instance");
+  }
+
+  var version = "1.10.2";
+
+  function userAgent(pattern) {
+    if (typeof window !== 'undefined' && window.navigator) {
+      return !!
+      /*@__PURE__*/
+      navigator.userAgent.match(pattern);
+    }
+  }
+
+  var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
+  var Edge = userAgent(/Edge/i);
+  var FireFox = userAgent(/firefox/i);
+  var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
+  var IOS = userAgent(/iP(ad|od|hone)/i);
+  var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
+
+  var captureMode = {
+    capture: false,
+    passive: false
+  };
+
+  function on(el, event, fn) {
+    el.addEventListener(event, fn, !IE11OrLess && captureMode);
+  }
+
+  function off(el, event, fn) {
+    el.removeEventListener(event, fn, !IE11OrLess && captureMode);
+  }
+
+  function matches(
+  /**HTMLElement*/
+  el,
+  /**String*/
+  selector) {
+    if (!selector) return;
+    selector[0] === '>' && (selector = selector.substring(1));
+
+    if (el) {
+      try {
+        if (el.matches) {
+          return el.matches(selector);
+        } else if (el.msMatchesSelector) {
+          return el.msMatchesSelector(selector);
+        } else if (el.webkitMatchesSelector) {
+          return el.webkitMatchesSelector(selector);
+        }
+      } catch (_) {
+        return false;
+      }
+    }
+
+    return false;
+  }
+
+  function getParentOrHost(el) {
+    return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
+  }
+
+  function closest(
+  /**HTMLElement*/
+  el,
+  /**String*/
+  selector,
+  /**HTMLElement*/
+  ctx, includeCTX) {
+    if (el) {
+      ctx = ctx || document;
+
+      do {
+        if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
+          return el;
+        }
+
+        if (el === ctx) break;
+        /* jshint boss:true */
+      } while (el = getParentOrHost(el));
+    }
+
+    return null;
+  }
+
+  var R_SPACE = /\s+/g;
+
+  function toggleClass(el, name, state) {
+    if (el && name) {
+      if (el.classList) {
+        el.classList[state ? 'add' : 'remove'](name);
+      } else {
+        var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
+        el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
+      }
+    }
+  }
+
+  function css(el, prop, val) {
+    var style = el && el.style;
+
+    if (style) {
+      if (val === void 0) {
+        if (document.defaultView && document.defaultView.getComputedStyle) {
+          val = document.defaultView.getComputedStyle(el, '');
+        } else if (el.currentStyle) {
+          val = el.currentStyle;
+        }
+
+        return prop === void 0 ? val : val[prop];
+      } else {
+        if (!(prop in style) && prop.indexOf('webkit') === -1) {
+          prop = '-webkit-' + prop;
+        }
+
+        style[prop] = val + (typeof val === 'string' ? '' : 'px');
+      }
+    }
+  }
+
+  function matrix(el, selfOnly) {
+    var appliedTransforms = '';
+
+    if (typeof el === 'string') {
+      appliedTransforms = el;
+    } else {
+      do {
+        var transform = css(el, 'transform');
+
+        if (transform && transform !== 'none') {
+          appliedTransforms = transform + ' ' + appliedTransforms;
+        }
+        /* jshint boss:true */
+
+      } while (!selfOnly && (el = el.parentNode));
+    }
+
+    var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
+    /*jshint -W056 */
+
+    return matrixFn && new matrixFn(appliedTransforms);
+  }
+
+  function find(ctx, tagName, iterator) {
+    if (ctx) {
+      var list = ctx.getElementsByTagName(tagName),
+          i = 0,
+          n = list.length;
+
+      if (iterator) {
+        for (; i < n; i++) {
+          iterator(list[i], i);
+        }
+      }
+
+      return list;
+    }
+
+    return [];
+  }
+
+  function getWindowScrollingElement() {
+    var scrollingElement = document.scrollingElement;
+
+    if (scrollingElement) {
+      return scrollingElement;
+    } else {
+      return document.documentElement;
+    }
+  }
+  /**
+   * Returns the "bounding client rect" of given element
+   * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
+   * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
+   * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
+   * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
+   * @param  {[HTMLElement]} container              The parent the element will be placed in
+   * @return {Object}                               The boundingClientRect of el, with specified adjustments
+   */
+
+
+  function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
+    if (!el.getBoundingClientRect && el !== window) return;
+    var elRect, top, left, bottom, right, height, width;
+
+    if (el !== window && el !== getWindowScrollingElement()) {
+      elRect = el.getBoundingClientRect();
+      top = elRect.top;
+      left = elRect.left;
+      bottom = elRect.bottom;
+      right = elRect.right;
+      height = elRect.height;
+      width = elRect.width;
+    } else {
+      top = 0;
+      left = 0;
+      bottom = window.innerHeight;
+      right = window.innerWidth;
+      height = window.innerHeight;
+      width = window.innerWidth;
+    }
+
+    if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
+      // Adjust for translate()
+      container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
+      // Not needed on <= IE11
+
+      if (!IE11OrLess) {
+        do {
+          if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
+            var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
+
+            top -= containerRect.top + parseInt(css(container, 'border-top-width'));
+            left -= containerRect.left + parseInt(css(container, 'border-left-width'));
+            bottom = top + elRect.height;
+            right = left + elRect.width;
+            break;
+          }
+          /* jshint boss:true */
+
+        } while (container = container.parentNode);
+      }
+    }
+
+    if (undoScale && el !== window) {
+      // Adjust for scale()
+      var elMatrix = matrix(container || el),
+          scaleX = elMatrix && elMatrix.a,
+          scaleY = elMatrix && elMatrix.d;
+
+      if (elMatrix) {
+        top /= scaleY;
+        left /= scaleX;
+        width /= scaleX;
+        height /= scaleY;
+        bottom = top + height;
+        right = left + width;
+      }
+    }
+
+    return {
+      top: top,
+      left: left,
+      bottom: bottom,
+      right: right,
+      width: width,
+      height: height
+    };
+  }
+  /**
+   * Checks if a side of an element is scrolled past a side of its parents
+   * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
+   * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
+   * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
+   * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
+   */
+
+
+  function isScrolledPast(el, elSide, parentSide) {
+    var parent = getParentAutoScrollElement(el, true),
+        elSideVal = getRect(el)[elSide];
+    /* jshint boss:true */
+
+    while (parent) {
+      var parentSideVal = getRect(parent)[parentSide],
+          visible = void 0;
+
+      if (parentSide === 'top' || parentSide === 'left') {
+        visible = elSideVal >= parentSideVal;
+      } else {
+        visible = elSideVal <= parentSideVal;
+      }
+
+      if (!visible) return parent;
+      if (parent === getWindowScrollingElement()) break;
+      parent = getParentAutoScrollElement(parent, false);
+    }
+
+    return false;
+  }
+  /**
+   * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
+   * and non-draggable elements
+   * @param  {HTMLElement} el       The parent element
+   * @param  {Number} childNum      The index of the child
+   * @param  {Object} options       Parent Sortable's options
+   * @return {HTMLElement}          The child at index childNum, or null if not found
+   */
+
+
+  function getChild(el, childNum, options) {
+    var currentChild = 0,
+        i = 0,
+        children = el.children;
+
+    while (i < children.length) {
+      if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && children[i] !== Sortable.dragged && closest(children[i], options.draggable, el, false)) {
+        if (currentChild === childNum) {
+          return children[i];
+        }
+
+        currentChild++;
+      }
+
+      i++;
+    }
+
+    return null;
+  }
+  /**
+   * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
+   * @param  {HTMLElement} el       Parent element
+   * @param  {selector} selector    Any other elements that should be ignored
+   * @return {HTMLElement}          The last child, ignoring ghostEl
+   */
+
+
+  function lastChild(el, selector) {
+    var last = el.lastElementChild;
+
+    while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
+      last = last.previousElementSibling;
+    }
+
+    return last || null;
+  }
+  /**
+   * Returns the index of an element within its parent for a selected set of
+   * elements
+   * @param  {HTMLElement} el
+   * @param  {selector} selector
+   * @return {number}
+   */
+
+
+  function index(el, selector) {
+    var index = 0;
+
+    if (!el || !el.parentNode) {
+      return -1;
+    }
+    /* jshint boss:true */
+
+
+    while (el = el.previousElementSibling) {
+      if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
+        index++;
+      }
+    }
+
+    return index;
+  }
+  /**
+   * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
+   * The value is returned in real pixels.
+   * @param  {HTMLElement} el
+   * @return {Array}             Offsets in the format of [left, top]
+   */
+
+
+  function getRelativeScrollOffset(el) {
+    var offsetLeft = 0,
+        offsetTop = 0,
+        winScroller = getWindowScrollingElement();
+
+    if (el) {
+      do {
+        var elMatrix = matrix(el),
+            scaleX = elMatrix.a,
+            scaleY = elMatrix.d;
+        offsetLeft += el.scrollLeft * scaleX;
+        offsetTop += el.scrollTop * scaleY;
+      } while (el !== winScroller && (el = el.parentNode));
+    }
+
+    return [offsetLeft, offsetTop];
+  }
+  /**
+   * Returns the index of the object within the given array
+   * @param  {Array} arr   Array that may or may not hold the object
+   * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
+   * @return {Number}      The index of the object in the array, or -1
+   */
+
+
+  function indexOfObject(arr, obj) {
+    for (var i in arr) {
+      if (!arr.hasOwnProperty(i)) continue;
+
+      for (var key in obj) {
+        if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
+      }
+    }
+
+    return -1;
+  }
+
+  function getParentAutoScrollElement(el, includeSelf) {
+    // skip to window
+    if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
+    var elem = el;
+    var gotSelf = false;
+
+    do {
+      // we don't need to get elem css if it isn't even overflowing in the first place (performance)
+      if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
+        var elemCSS = css(elem);
+
+        if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
+          if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
+          if (gotSelf || includeSelf) return elem;
+          gotSelf = true;
+        }
+      }
+      /* jshint boss:true */
+
+    } while (elem = elem.parentNode);
+
+    return getWindowScrollingElement();
+  }
+
+  function extend(dst, src) {
+    if (dst && src) {
+      for (var key in src) {
+        if (src.hasOwnProperty(key)) {
+          dst[key] = src[key];
+        }
+      }
+    }
+
+    return dst;
+  }
+
+  function isRectEqual(rect1, rect2) {
+    return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
+  }
+
+  var _throttleTimeout;
+
+  function throttle(callback, ms) {
+    return function () {
+      if (!_throttleTimeout) {
+        var args = arguments,
+            _this = this;
+
+        if (args.length === 1) {
+          callback.call(_this, args[0]);
+        } else {
+          callback.apply(_this, args);
+        }
+
+        _throttleTimeout = setTimeout(function () {
+          _throttleTimeout = void 0;
+        }, ms);
+      }
+    };
+  }
+
+  function cancelThrottle() {
+    clearTimeout(_throttleTimeout);
+    _throttleTimeout = void 0;
+  }
+
+  function scrollBy(el, x, y) {
+    el.scrollLeft += x;
+    el.scrollTop += y;
+  }
+
+  function clone(el) {
+    var Polymer = window.Polymer;
+    var $ = window.jQuery || window.Zepto;
+
+    if (Polymer && Polymer.dom) {
+      return Polymer.dom(el).cloneNode(true);
+    } else if ($) {
+      return $(el).clone(true)[0];
+    } else {
+      return el.cloneNode(true);
+    }
+  }
+
+  function setRect(el, rect) {
+    css(el, 'position', 'absolute');
+    css(el, 'top', rect.top);
+    css(el, 'left', rect.left);
+    css(el, 'width', rect.width);
+    css(el, 'height', rect.height);
+  }
+
+  function unsetRect(el) {
+    css(el, 'position', '');
+    css(el, 'top', '');
+    css(el, 'left', '');
+    css(el, 'width', '');
+    css(el, 'height', '');
+  }
+
+  var expando = 'Sortable' + new Date().getTime();
+
+  function AnimationStateManager() {
+    var animationStates = [],
+        animationCallbackId;
+    return {
+      captureAnimationState: function captureAnimationState() {
+        animationStates = [];
+        if (!this.options.animation) return;
+        var children = [].slice.call(this.el.children);
+        children.forEach(function (child) {
+          if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
+          animationStates.push({
+            target: child,
+            rect: getRect(child)
+          });
+
+          var fromRect = _objectSpread({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation
+
+
+          if (child.thisAnimationDuration) {
+            var childMatrix = matrix(child, true);
+
+            if (childMatrix) {
+              fromRect.top -= childMatrix.f;
+              fromRect.left -= childMatrix.e;
+            }
+          }
+
+          child.fromRect = fromRect;
+        });
+      },
+      addAnimationState: function addAnimationState(state) {
+        animationStates.push(state);
+      },
+      removeAnimationState: function removeAnimationState(target) {
+        animationStates.splice(indexOfObject(animationStates, {
+          target: target
+        }), 1);
+      },
+      animateAll: function animateAll(callback) {
+        var _this = this;
+
+        if (!this.options.animation) {
+          clearTimeout(animationCallbackId);
+          if (typeof callback === 'function') callback();
+          return;
+        }
+
+        var animating = false,
+            animationTime = 0;
+        animationStates.forEach(function (state) {
+          var time = 0,
+              target = state.target,
+              fromRect = target.fromRect,
+              toRect = getRect(target),
+              prevFromRect = target.prevFromRect,
+              prevToRect = target.prevToRect,
+              animatingRect = state.rect,
+              targetMatrix = matrix(target, true);
+
+          if (targetMatrix) {
+            // Compensate for current animation
+            toRect.top -= targetMatrix.f;
+            toRect.left -= targetMatrix.e;
+          }
+
+          target.toRect = toRect;
+
+          if (target.thisAnimationDuration) {
+            // Could also check if animatingRect is between fromRect and toRect
+            if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
+            (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
+              // If returning to same place as started from animation and on same axis
+              time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
+            }
+          } // if fromRect != toRect: animate
+
+
+          if (!isRectEqual(toRect, fromRect)) {
+            target.prevFromRect = fromRect;
+            target.prevToRect = toRect;
+
+            if (!time) {
+              time = _this.options.animation;
+            }
+
+            _this.animate(target, animatingRect, toRect, time);
+          }
+
+          if (time) {
+            animating = true;
+            animationTime = Math.max(animationTime, time);
+            clearTimeout(target.animationResetTimer);
+            target.animationResetTimer = setTimeout(function () {
+              target.animationTime = 0;
+              target.prevFromRect = null;
+              target.fromRect = null;
+              target.prevToRect = null;
+              target.thisAnimationDuration = null;
+            }, time);
+            target.thisAnimationDuration = time;
+          }
+        });
+        clearTimeout(animationCallbackId);
+
+        if (!animating) {
+          if (typeof callback === 'function') callback();
+        } else {
+          animationCallbackId = setTimeout(function () {
+            if (typeof callback === 'function') callback();
+          }, animationTime);
+        }
+
+        animationStates = [];
+      },
+      animate: function animate(target, currentRect, toRect, duration) {
+        if (duration) {
+          css(target, 'transition', '');
+          css(target, 'transform', '');
+          var elMatrix = matrix(this.el),
+              scaleX = elMatrix && elMatrix.a,
+              scaleY = elMatrix && elMatrix.d,
+              translateX = (currentRect.left - toRect.left) / (scaleX || 1),
+              translateY = (currentRect.top - toRect.top) / (scaleY || 1);
+          target.animatingX = !!translateX;
+          target.animatingY = !!translateY;
+          css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
+          repaint(target); // repaint
+
+          css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
+          css(target, 'transform', 'translate3d(0,0,0)');
+          typeof target.animated === 'number' && clearTimeout(target.animated);
+          target.animated = setTimeout(function () {
+            css(target, 'transition', '');
+            css(target, 'transform', '');
+            target.animated = false;
+            target.animatingX = false;
+            target.animatingY = false;
+          }, duration);
+        }
+      }
+    };
+  }
+
+  function repaint(target) {
+    return target.offsetWidth;
+  }
+
+  function calculateRealTime(animatingRect, fromRect, toRect, options) {
+    return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
+  }
+
+  var plugins = [];
+  var defaults = {
+    initializeByDefault: true
+  };
+  var PluginManager = {
+    mount: function mount(plugin) {
+      // Set default static properties
+      for (var option in defaults) {
+        if (defaults.hasOwnProperty(option) && !(option in plugin)) {
+          plugin[option] = defaults[option];
+        }
+      }
+
+      plugins.push(plugin);
+    },
+    pluginEvent: function pluginEvent(eventName, sortable, evt) {
+      var _this = this;
+
+      this.eventCanceled = false;
+
+      evt.cancel = function () {
+        _this.eventCanceled = true;
+      };
+
+      var eventNameGlobal = eventName + 'Global';
+      plugins.forEach(function (plugin) {
+        if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
+
+        if (sortable[plugin.pluginName][eventNameGlobal]) {
+          sortable[plugin.pluginName][eventNameGlobal](_objectSpread({
+            sortable: sortable
+          }, evt));
+        } // Only fire plugin event if plugin is enabled in this sortable,
+        // and plugin has event defined
+
+
+        if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
+          sortable[plugin.pluginName][eventName](_objectSpread({
+            sortable: sortable
+          }, evt));
+        }
+      });
+    },
+    initializePlugins: function initializePlugins(sortable, el, defaults, options) {
+      plugins.forEach(function (plugin) {
+        var pluginName = plugin.pluginName;
+        if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
+        var initialized = new plugin(sortable, el, sortable.options);
+        initialized.sortable = sortable;
+        initialized.options = sortable.options;
+        sortable[pluginName] = initialized; // Add default options from plugin
+
+        _extends(defaults, initialized.defaults);
+      });
+
+      for (var option in sortable.options) {
+        if (!sortable.options.hasOwnProperty(option)) continue;
+        var modified = this.modifyOption(sortable, option, sortable.options[option]);
+
+        if (typeof modified !== 'undefined') {
+          sortable.options[option] = modified;
+        }
+      }
+    },
+    getEventProperties: function getEventProperties(name, sortable) {
+      var eventProperties = {};
+      plugins.forEach(function (plugin) {
+        if (typeof plugin.eventProperties !== 'function') return;
+
+        _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
+      });
+      return eventProperties;
+    },
+    modifyOption: function modifyOption(sortable, name, value) {
+      var modifiedValue;
+      plugins.forEach(function (plugin) {
+        // Plugin must exist on the Sortable
+        if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
+
+        if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
+          modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
+        }
+      });
+      return modifiedValue;
+    }
+  };
+
+  function dispatchEvent(_ref) {
+    var sortable = _ref.sortable,
+        rootEl = _ref.rootEl,
+        name = _ref.name,
+        targetEl = _ref.targetEl,
+        cloneEl = _ref.cloneEl,
+        toEl = _ref.toEl,
+        fromEl = _ref.fromEl,
+        oldIndex = _ref.oldIndex,
+        newIndex = _ref.newIndex,
+        oldDraggableIndex = _ref.oldDraggableIndex,
+        newDraggableIndex = _ref.newDraggableIndex,
+        originalEvent = _ref.originalEvent,
+        putSortable = _ref.putSortable,
+        extraEventProperties = _ref.extraEventProperties;
+    sortable = sortable || rootEl && rootEl[expando];
+    if (!sortable) return;
+    var evt,
+        options = sortable.options,
+        onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
+
+    if (window.CustomEvent && !IE11OrLess && !Edge) {
+      evt = new CustomEvent(name, {
+        bubbles: true,
+        cancelable: true
+      });
+    } else {
+      evt = document.createEvent('Event');
+      evt.initEvent(name, true, true);
+    }
+
+    evt.to = toEl || rootEl;
+    evt.from = fromEl || rootEl;
+    evt.item = targetEl || rootEl;
+    evt.clone = cloneEl;
+    evt.oldIndex = oldIndex;
+    evt.newIndex = newIndex;
+    evt.oldDraggableIndex = oldDraggableIndex;
+    evt.newDraggableIndex = newDraggableIndex;
+    evt.originalEvent = originalEvent;
+    evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
+
+    var allEventProperties = _objectSpread({}, extraEventProperties, PluginManager.getEventProperties(name, sortable));
+
+    for (var option in allEventProperties) {
+      evt[option] = allEventProperties[option];
+    }
+
+    if (rootEl) {
+      rootEl.dispatchEvent(evt);
+    }
+
+    if (options[onName]) {
+      options[onName].call(sortable, evt);
+    }
+  }
+
+  var pluginEvent = function pluginEvent(eventName, sortable) {
+    var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
+        originalEvent = _ref.evt,
+        data = _objectWithoutProperties(_ref, ["evt"]);
+
+    PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread({
+      dragEl: dragEl,
+      parentEl: parentEl,
+      ghostEl: ghostEl,
+      rootEl: rootEl,
+      nextEl: nextEl,
+      lastDownEl: lastDownEl,
+      cloneEl: cloneEl,
+      cloneHidden: cloneHidden,
+      dragStarted: moved,
+      putSortable: putSortable,
+      activeSortable: Sortable.active,
+      originalEvent: originalEvent,
+      oldIndex: oldIndex,
+      oldDraggableIndex: oldDraggableIndex,
+      newIndex: newIndex,
+      newDraggableIndex: newDraggableIndex,
+      hideGhostForTarget: _hideGhostForTarget,
+      unhideGhostForTarget: _unhideGhostForTarget,
+      cloneNowHidden: function cloneNowHidden() {
+        cloneHidden = true;
+      },
+      cloneNowShown: function cloneNowShown() {
+        cloneHidden = false;
+      },
+      dispatchSortableEvent: function dispatchSortableEvent(name) {
+        _dispatchEvent({
+          sortable: sortable,
+          name: name,
+          originalEvent: originalEvent
+        });
+      }
+    }, data));
+  };
+
+  function _dispatchEvent(info) {
+    dispatchEvent(_objectSpread({
+      putSortable: putSortable,
+      cloneEl: cloneEl,
+      targetEl: dragEl,
+      rootEl: rootEl,
+      oldIndex: oldIndex,
+      oldDraggableIndex: oldDraggableIndex,
+      newIndex: newIndex,
+      newDraggableIndex: newDraggableIndex
+    }, info));
+  }
+
+  var dragEl,
+      parentEl,
+      ghostEl,
+      rootEl,
+      nextEl,
+      lastDownEl,
+      cloneEl,
+      cloneHidden,
+      oldIndex,
+      newIndex,
+      oldDraggableIndex,
+      newDraggableIndex,
+      activeGroup,
+      putSortable,
+      awaitingDragStarted = false,
+      ignoreNextClick = false,
+      sortables = [],
+      tapEvt,
+      touchEvt,
+      lastDx,
+      lastDy,
+      tapDistanceLeft,
+      tapDistanceTop,
+      moved,
+      lastTarget,
+      lastDirection,
+      pastFirstInvertThresh = false,
+      isCircumstantialInvert = false,
+      targetMoveDistance,
+      // For positioning ghost absolutely
+  ghostRelativeParent,
+      ghostRelativeParentInitialScroll = [],
+      // (left, top)
+  _silent = false,
+      savedInputChecked = [];
+  /** @const */
+
+  var documentExists = typeof document !== 'undefined',
+      PositionGhostAbsolutely = IOS,
+      CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
+      // This will not pass for IE9, because IE9 DnD only works on anchors
+  supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
+      supportCssPointerEvents = function () {
+    if (!documentExists) return; // false when <= IE11
+
+    if (IE11OrLess) {
+      return false;
+    }
+
+    var el = document.createElement('x');
+    el.style.cssText = 'pointer-events:auto';
+    return el.style.pointerEvents === 'auto';
+  }(),
+      _detectDirection = function _detectDirection(el, options) {
+    var elCSS = css(el),
+        elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
+        child1 = getChild(el, 0, options),
+        child2 = getChild(el, 1, options),
+        firstChildCSS = child1 && css(child1),
+        secondChildCSS = child2 && css(child2),
+        firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
+        secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
+
+    if (elCSS.display === 'flex') {
+      return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
+    }
+
+    if (elCSS.display === 'grid') {
+      return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
+    }
+
+    if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
+      var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
+      return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
+    }
+
+    return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
+  },
+      _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
+    var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
+        dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
+        dragElOppLength = vertical ? dragRect.width : dragRect.height,
+        targetS1Opp = vertical ? targetRect.left : targetRect.top,
+        targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
+        targetOppLength = vertical ? targetRect.width : targetRect.height;
+    return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
+  },
+
+  /**
+   * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
+   * @param  {Number} x      X position
+   * @param  {Number} y      Y position
+   * @return {HTMLElement}   Element of the first found nearest Sortable
+   */
+  _detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
+    var ret;
+    sortables.some(function (sortable) {
+      if (lastChild(sortable)) return;
+      var rect = getRect(sortable),
+          threshold = sortable[expando].options.emptyInsertThreshold,
+          insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
+          insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
+
+      if (threshold && insideHorizontally && insideVertically) {
+        return ret = sortable;
+      }
+    });
+    return ret;
+  },
+      _prepareGroup = function _prepareGroup(options) {
+    function toFn(value, pull) {
+      return function (to, from, dragEl, evt) {
+        var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
+
+        if (value == null && (pull || sameGroup)) {
+          // Default pull value
+          // Default pull and put value if same group
+          return true;
+        } else if (value == null || value === false) {
+          return false;
+        } else if (pull && value === 'clone') {
+          return value;
+        } else if (typeof value === 'function') {
+          return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
+        } else {
+          var otherGroup = (pull ? to : from).options.group.name;
+          return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
+        }
+      };
+    }
+
+    var group = {};
+    var originalGroup = options.group;
+
+    if (!originalGroup || _typeof(originalGroup) != 'object') {
+      originalGroup = {
+        name: originalGroup
+      };
+    }
+
+    group.name = originalGroup.name;
+    group.checkPull = toFn(originalGroup.pull, true);
+    group.checkPut = toFn(originalGroup.put);
+    group.revertClone = originalGroup.revertClone;
+    options.group = group;
+  },
+      _hideGhostForTarget = function _hideGhostForTarget() {
+    if (!supportCssPointerEvents && ghostEl) {
+      css(ghostEl, 'display', 'none');
+    }
+  },
+      _unhideGhostForTarget = function _unhideGhostForTarget() {
+    if (!supportCssPointerEvents && ghostEl) {
+      css(ghostEl, 'display', '');
+    }
+  }; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
+
+
+  if (documentExists) {
+    document.addEventListener('click', function (evt) {
+      if (ignoreNextClick) {
+        evt.preventDefault();
+        evt.stopPropagation && evt.stopPropagation();
+        evt.stopImmediatePropagation && evt.stopImmediatePropagation();
+        ignoreNextClick = false;
+        return false;
+      }
+    }, true);
+  }
+
+  var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
+    if (dragEl) {
+      evt = evt.touches ? evt.touches[0] : evt;
+
+      var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
+
+      if (nearest) {
+        // Create imitation event
+        var event = {};
+
+        for (var i in evt) {
+          if (evt.hasOwnProperty(i)) {
+            event[i] = evt[i];
+          }
+        }
+
+        event.target = event.rootEl = nearest;
+        event.preventDefault = void 0;
+        event.stopPropagation = void 0;
+
+        nearest[expando]._onDragOver(event);
+      }
+    }
+  };
+
+  var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
+    if (dragEl) {
+      dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
+    }
+  };
+  /**
+   * @class  Sortable
+   * @param  {HTMLElement}  el
+   * @param  {Object}       [options]
+   */
+
+
+  function Sortable(el, options) {
+    if (!(el && el.nodeType && el.nodeType === 1)) {
+      throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
+    }
+
+    this.el = el; // root element
+
+    this.options = options = _extends({}, options); // Export instance
+
+    el[expando] = this;
+    var defaults = {
+      group: null,
+      sort: true,
+      disabled: false,
+      store: null,
+      handle: null,
+      draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
+      swapThreshold: 1,
+      // percentage; 0 <= x <= 1
+      invertSwap: false,
+      // invert always
+      invertedSwapThreshold: null,
+      // will be set to same as swapThreshold if default
+      removeCloneOnHide: true,
+      direction: function direction() {
+        return _detectDirection(el, this.options);
+      },
+      ghostClass: 'sortable-ghost',
+      chosenClass: 'sortable-chosen',
+      dragClass: 'sortable-drag',
+      ignore: 'a, img',
+      filter: null,
+      preventOnFilter: true,
+      animation: 0,
+      easing: null,
+      setData: function setData(dataTransfer, dragEl) {
+        dataTransfer.setData('Text', dragEl.textContent);
+      },
+      dropBubble: false,
+      dragoverBubble: false,
+      dataIdAttr: 'data-id',
+      delay: 0,
+      delayOnTouchOnly: false,
+      touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
+      forceFallback: false,
+      fallbackClass: 'sortable-fallback',
+      fallbackOnBody: false,
+      fallbackTolerance: 0,
+      fallbackOffset: {
+        x: 0,
+        y: 0
+      },
+      supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window,
+      emptyInsertThreshold: 5
+    };
+    PluginManager.initializePlugins(this, el, defaults); // Set default options
+
+    for (var name in defaults) {
+      !(name in options) && (options[name] = defaults[name]);
+    }
+
+    _prepareGroup(options); // Bind all private methods
+
+
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    } // Setup drag mode
+
+
+    this.nativeDraggable = options.forceFallback ? false : supportDraggable;
+
+    if (this.nativeDraggable) {
+      // Touch start threshold cannot be greater than the native dragstart threshold
+      this.options.touchStartThreshold = 1;
+    } // Bind events
+
+
+    if (options.supportPointer) {
+      on(el, 'pointerdown', this._onTapStart);
+    } else {
+      on(el, 'mousedown', this._onTapStart);
+      on(el, 'touchstart', this._onTapStart);
+    }
+
+    if (this.nativeDraggable) {
+      on(el, 'dragover', this);
+      on(el, 'dragenter', this);
+    }
+
+    sortables.push(this.el); // Restore sorting
+
+    options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
+
+    _extends(this, AnimationStateManager());
+  }
+
+  Sortable.prototype =
+  /** @lends Sortable.prototype */
+  {
+    constructor: Sortable,
+    _isOutsideThisEl: function _isOutsideThisEl(target) {
+      if (!this.el.contains(target) && target !== this.el) {
+        lastTarget = null;
+      }
+    },
+    _getDirection: function _getDirection(evt, target) {
+      return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
+    },
+    _onTapStart: function _onTapStart(
+    /** Event|TouchEvent */
+    evt) {
+      if (!evt.cancelable) return;
+
+      var _this = this,
+          el = this.el,
+          options = this.options,
+          preventOnFilter = options.preventOnFilter,
+          type = evt.type,
+          touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
+          target = (touch || evt).target,
+          originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
+          filter = options.filter;
+
+      _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
+
+
+      if (dragEl) {
+        return;
+      }
+
+      if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
+        return; // only left button and enabled
+      } // cancel dnd if original target is content editable
+
+
+      if (originalTarget.isContentEditable) {
+        return;
+      }
+
+      target = closest(target, options.draggable, el, false);
+
+      if (target && target.animated) {
+        return;
+      }
+
+      if (lastDownEl === target) {
+        // Ignoring duplicate `down`
+        return;
+      } // Get the index of the dragged element within its parent
+
+
+      oldIndex = index(target);
+      oldDraggableIndex = index(target, options.draggable); // Check filter
+
+      if (typeof filter === 'function') {
+        if (filter.call(this, evt, target, this)) {
+          _dispatchEvent({
+            sortable: _this,
+            rootEl: originalTarget,
+            name: 'filter',
+            targetEl: target,
+            toEl: el,
+            fromEl: el
+          });
+
+          pluginEvent('filter', _this, {
+            evt: evt
+          });
+          preventOnFilter && evt.cancelable && evt.preventDefault();
+          return; // cancel dnd
+        }
+      } else if (filter) {
+        filter = filter.split(',').some(function (criteria) {
+          criteria = closest(originalTarget, criteria.trim(), el, false);
+
+          if (criteria) {
+            _dispatchEvent({
+              sortable: _this,
+              rootEl: criteria,
+              name: 'filter',
+              targetEl: target,
+              fromEl: el,
+              toEl: el
+            });
+
+            pluginEvent('filter', _this, {
+              evt: evt
+            });
+            return true;
+          }
+        });
+
+        if (filter) {
+          preventOnFilter && evt.cancelable && evt.preventDefault();
+          return; // cancel dnd
+        }
+      }
+
+      if (options.handle && !closest(originalTarget, options.handle, el, false)) {
+        return;
+      } // Prepare `dragstart`
+
+
+      this._prepareDragStart(evt, touch, target);
+    },
+    _prepareDragStart: function _prepareDragStart(
+    /** Event */
+    evt,
+    /** Touch */
+    touch,
+    /** HTMLElement */
+    target) {
+      var _this = this,
+          el = _this.el,
+          options = _this.options,
+          ownerDocument = el.ownerDocument,
+          dragStartFn;
+
+      if (target && !dragEl && target.parentNode === el) {
+        var dragRect = getRect(target);
+        rootEl = el;
+        dragEl = target;
+        parentEl = dragEl.parentNode;
+        nextEl = dragEl.nextSibling;
+        lastDownEl = target;
+        activeGroup = options.group;
+        Sortable.dragged = dragEl;
+        tapEvt = {
+          target: dragEl,
+          clientX: (touch || evt).clientX,
+          clientY: (touch || evt).clientY
+        };
+        tapDistanceLeft = tapEvt.clientX - dragRect.left;
+        tapDistanceTop = tapEvt.clientY - dragRect.top;
+        this._lastX = (touch || evt).clientX;
+        this._lastY = (touch || evt).clientY;
+        dragEl.style['will-change'] = 'all';
+
+        dragStartFn = function dragStartFn() {
+          pluginEvent('delayEnded', _this, {
+            evt: evt
+          });
+
+          if (Sortable.eventCanceled) {
+            _this._onDrop();
+
+            return;
+          } // Delayed drag has been triggered
+          // we can re-enable the events: touchmove/mousemove
+
+
+          _this._disableDelayedDragEvents();
+
+          if (!FireFox && _this.nativeDraggable) {
+            dragEl.draggable = true;
+          } // Bind the events: dragstart/dragend
+
+
+          _this._triggerDragStart(evt, touch); // Drag start event
+
+
+          _dispatchEvent({
+            sortable: _this,
+            name: 'choose',
+            originalEvent: evt
+          }); // Chosen item
+
+
+          toggleClass(dragEl, options.chosenClass, true);
+        }; // Disable "draggable"
+
+
+        options.ignore.split(',').forEach(function (criteria) {
+          find(dragEl, criteria.trim(), _disableDraggable);
+        });
+        on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
+        on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
+        on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
+        on(ownerDocument, 'mouseup', _this._onDrop);
+        on(ownerDocument, 'touchend', _this._onDrop);
+        on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
+
+        if (FireFox && this.nativeDraggable) {
+          this.options.touchStartThreshold = 4;
+          dragEl.draggable = true;
+        }
+
+        pluginEvent('delayStart', this, {
+          evt: evt
+        }); // Delay is impossible for native DnD in Edge or IE
+
+        if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
+          if (Sortable.eventCanceled) {
+            this._onDrop();
+
+            return;
+          } // If the user moves the pointer or let go the click or touch
+          // before the delay has been reached:
+          // disable the delayed drag
+
+
+          on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
+          on(ownerDocument, 'touchend', _this._disableDelayedDrag);
+          on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
+          on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
+          on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
+          options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
+          _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
+        } else {
+          dragStartFn();
+        }
+      }
+    },
+    _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
+    /** TouchEvent|PointerEvent **/
+    e) {
+      var touch = e.touches ? e.touches[0] : e;
+
+      if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
+        this._disableDelayedDrag();
+      }
+    },
+    _disableDelayedDrag: function _disableDelayedDrag() {
+      dragEl && _disableDraggable(dragEl);
+      clearTimeout(this._dragStartTimer);
+
+      this._disableDelayedDragEvents();
+    },
+    _disableDelayedDragEvents: function _disableDelayedDragEvents() {
+      var ownerDocument = this.el.ownerDocument;
+      off(ownerDocument, 'mouseup', this._disableDelayedDrag);
+      off(ownerDocument, 'touchend', this._disableDelayedDrag);
+      off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
+      off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
+      off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
+      off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
+    },
+    _triggerDragStart: function _triggerDragStart(
+    /** Event */
+    evt,
+    /** Touch */
+    touch) {
+      touch = touch || evt.pointerType == 'touch' && evt;
+
+      if (!this.nativeDraggable || touch) {
+        if (this.options.supportPointer) {
+          on(document, 'pointermove', this._onTouchMove);
+        } else if (touch) {
+          on(document, 'touchmove', this._onTouchMove);
+        } else {
+          on(document, 'mousemove', this._onTouchMove);
+        }
+      } else {
+        on(dragEl, 'dragend', this);
+        on(rootEl, 'dragstart', this._onDragStart);
+      }
+
+      try {
+        if (document.selection) {
+          // Timeout neccessary for IE9
+          _nextTick(function () {
+            document.selection.empty();
+          });
+        } else {
+          window.getSelection().removeAllRanges();
+        }
+      } catch (err) {}
+    },
+    _dragStarted: function _dragStarted(fallback, evt) {
+
+      awaitingDragStarted = false;
+
+      if (rootEl && dragEl) {
+        pluginEvent('dragStarted', this, {
+          evt: evt
+        });
+
+        if (this.nativeDraggable) {
+          on(document, 'dragover', _checkOutsideTargetEl);
+        }
+
+        var options = this.options; // Apply effect
+
+        !fallback && toggleClass(dragEl, options.dragClass, false);
+        toggleClass(dragEl, options.ghostClass, true);
+        Sortable.active = this;
+        fallback && this._appendGhost(); // Drag start event
+
+        _dispatchEvent({
+          sortable: this,
+          name: 'start',
+          originalEvent: evt
+        });
+      } else {
+        this._nulling();
+      }
+    },
+    _emulateDragOver: function _emulateDragOver() {
+      if (touchEvt) {
+        this._lastX = touchEvt.clientX;
+        this._lastY = touchEvt.clientY;
+
+        _hideGhostForTarget();
+
+        var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+        var parent = target;
+
+        while (target && target.shadowRoot) {
+          target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+          if (target === parent) break;
+          parent = target;
+        }
+
+        dragEl.parentNode[expando]._isOutsideThisEl(target);
+
+        if (parent) {
+          do {
+            if (parent[expando]) {
+              var inserted = void 0;
+              inserted = parent[expando]._onDragOver({
+                clientX: touchEvt.clientX,
+                clientY: touchEvt.clientY,
+                target: target,
+                rootEl: parent
+              });
+
+              if (inserted && !this.options.dragoverBubble) {
+                break;
+              }
+            }
+
+            target = parent; // store last element
+          }
+          /* jshint boss:true */
+          while (parent = parent.parentNode);
+        }
+
+        _unhideGhostForTarget();
+      }
+    },
+    _onTouchMove: function _onTouchMove(
+    /**TouchEvent*/
+    evt) {
+      if (tapEvt) {
+        var options = this.options,
+            fallbackTolerance = options.fallbackTolerance,
+            fallbackOffset = options.fallbackOffset,
+            touch = evt.touches ? evt.touches[0] : evt,
+            ghostMatrix = ghostEl && matrix(ghostEl, true),
+            scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
+            scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
+            relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
+            dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
+            dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging
+
+        if (!Sortable.active && !awaitingDragStarted) {
+          if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
+            return;
+          }
+
+          this._onDragStart(evt, true);
+        }
+
+        if (ghostEl) {
+          if (ghostMatrix) {
+            ghostMatrix.e += dx - (lastDx || 0);
+            ghostMatrix.f += dy - (lastDy || 0);
+          } else {
+            ghostMatrix = {
+              a: 1,
+              b: 0,
+              c: 0,
+              d: 1,
+              e: dx,
+              f: dy
+            };
+          }
+
+          var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
+          css(ghostEl, 'webkitTransform', cssMatrix);
+          css(ghostEl, 'mozTransform', cssMatrix);
+          css(ghostEl, 'msTransform', cssMatrix);
+          css(ghostEl, 'transform', cssMatrix);
+          lastDx = dx;
+          lastDy = dy;
+          touchEvt = touch;
+        }
+
+        evt.cancelable && evt.preventDefault();
+      }
+    },
+    _appendGhost: function _appendGhost() {
+      // Bug if using scale(): https://stackoverflow.com/questions/2637058
+      // Not being adjusted for
+      if (!ghostEl) {
+        var container = this.options.fallbackOnBody ? document.body : rootEl,
+            rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
+            options = this.options; // Position absolutely
+
+        if (PositionGhostAbsolutely) {
+          // Get relatively positioned parent
+          ghostRelativeParent = container;
+
+          while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
+            ghostRelativeParent = ghostRelativeParent.parentNode;
+          }
+
+          if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
+            if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
+            rect.top += ghostRelativeParent.scrollTop;
+            rect.left += ghostRelativeParent.scrollLeft;
+          } else {
+            ghostRelativeParent = getWindowScrollingElement();
+          }
+
+          ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
+        }
+
+        ghostEl = dragEl.cloneNode(true);
+        toggleClass(ghostEl, options.ghostClass, false);
+        toggleClass(ghostEl, options.fallbackClass, true);
+        toggleClass(ghostEl, options.dragClass, true);
+        css(ghostEl, 'transition', '');
+        css(ghostEl, 'transform', '');
+        css(ghostEl, 'box-sizing', 'border-box');
+        css(ghostEl, 'margin', 0);
+        css(ghostEl, 'top', rect.top);
+        css(ghostEl, 'left', rect.left);
+        css(ghostEl, 'width', rect.width);
+        css(ghostEl, 'height', rect.height);
+        css(ghostEl, 'opacity', '0.8');
+        css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
+        css(ghostEl, 'zIndex', '100000');
+        css(ghostEl, 'pointerEvents', 'none');
+        Sortable.ghost = ghostEl;
+        container.appendChild(ghostEl); // Set transform-origin
+
+        css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
+      }
+    },
+    _onDragStart: function _onDragStart(
+    /**Event*/
+    evt,
+    /**boolean*/
+    fallback) {
+      var _this = this;
+
+      var dataTransfer = evt.dataTransfer;
+      var options = _this.options;
+      pluginEvent('dragStart', this, {
+        evt: evt
+      });
+
+      if (Sortable.eventCanceled) {
+        this._onDrop();
+
+        return;
+      }
+
+      pluginEvent('setupClone', this);
+
+      if (!Sortable.eventCanceled) {
+        cloneEl = clone(dragEl);
+        cloneEl.draggable = false;
+        cloneEl.style['will-change'] = '';
+
+        this._hideClone();
+
+        toggleClass(cloneEl, this.options.chosenClass, false);
+        Sortable.clone = cloneEl;
+      } // #1143: IFrame support workaround
+
+
+      _this.cloneId = _nextTick(function () {
+        pluginEvent('clone', _this);
+        if (Sortable.eventCanceled) return;
+
+        if (!_this.options.removeCloneOnHide) {
+          rootEl.insertBefore(cloneEl, dragEl);
+        }
+
+        _this._hideClone();
+
+        _dispatchEvent({
+          sortable: _this,
+          name: 'clone'
+        });
+      });
+      !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
+
+      if (fallback) {
+        ignoreNextClick = true;
+        _this._loopId = setInterval(_this._emulateDragOver, 50);
+      } else {
+        // Undo what was set in _prepareDragStart before drag started
+        off(document, 'mouseup', _this._onDrop);
+        off(document, 'touchend', _this._onDrop);
+        off(document, 'touchcancel', _this._onDrop);
+
+        if (dataTransfer) {
+          dataTransfer.effectAllowed = 'move';
+          options.setData && options.setData.call(_this, dataTransfer, dragEl);
+        }
+
+        on(document, 'drop', _this); // #1276 fix:
+
+        css(dragEl, 'transform', 'translateZ(0)');
+      }
+
+      awaitingDragStarted = true;
+      _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
+      on(document, 'selectstart', _this);
+      moved = true;
+
+      if (Safari) {
+        css(document.body, 'user-select', 'none');
+      }
+    },
+    // Returns true - if no further action is needed (either inserted or another condition)
+    _onDragOver: function _onDragOver(
+    /**Event*/
+    evt) {
+      var el = this.el,
+          target = evt.target,
+          dragRect,
+          targetRect,
+          revert,
+          options = this.options,
+          group = options.group,
+          activeSortable = Sortable.active,
+          isOwner = activeGroup === group,
+          canSort = options.sort,
+          fromSortable = putSortable || activeSortable,
+          vertical,
+          _this = this,
+          completedFired = false;
+
+      if (_silent) return;
+
+      function dragOverEvent(name, extra) {
+        pluginEvent(name, _this, _objectSpread({
+          evt: evt,
+          isOwner: isOwner,
+          axis: vertical ? 'vertical' : 'horizontal',
+          revert: revert,
+          dragRect: dragRect,
+          targetRect: targetRect,
+          canSort: canSort,
+          fromSortable: fromSortable,
+          target: target,
+          completed: completed,
+          onMove: function onMove(target, after) {
+            return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
+          },
+          changed: changed
+        }, extra));
+      } // Capture animation state
+
+
+      function capture() {
+        dragOverEvent('dragOverAnimationCapture');
+
+        _this.captureAnimationState();
+
+        if (_this !== fromSortable) {
+          fromSortable.captureAnimationState();
+        }
+      } // Return invocation when dragEl is inserted (or completed)
+
+
+      function completed(insertion) {
+        dragOverEvent('dragOverCompleted', {
+          insertion: insertion
+        });
+
+        if (insertion) {
+          // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+          if (isOwner) {
+            activeSortable._hideClone();
+          } else {
+            activeSortable._showClone(_this);
+          }
+
+          if (_this !== fromSortable) {
+            // Set ghost class to new sortable's ghost class
+            toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
+            toggleClass(dragEl, options.ghostClass, true);
+          }
+
+          if (putSortable !== _this && _this !== Sortable.active) {
+            putSortable = _this;
+          } else if (_this === Sortable.active && putSortable) {
+            putSortable = null;
+          } // Animation
+
+
+          if (fromSortable === _this) {
+            _this._ignoreWhileAnimating = target;
+          }
+
+          _this.animateAll(function () {
+            dragOverEvent('dragOverAnimationComplete');
+            _this._ignoreWhileAnimating = null;
+          });
+
+          if (_this !== fromSortable) {
+            fromSortable.animateAll();
+            fromSortable._ignoreWhileAnimating = null;
+          }
+        } // Null lastTarget if it is not inside a previously swapped element
+
+
+        if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
+          lastTarget = null;
+        } // no bubbling and not fallback
+
+
+        if (!options.dragoverBubble && !evt.rootEl && target !== document) {
+          dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
+
+
+          !insertion && nearestEmptyInsertDetectEvent(evt);
+        }
+
+        !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
+        return completedFired = true;
+      } // Call when dragEl has been inserted
+
+
+      function changed() {
+        newIndex = index(dragEl);
+        newDraggableIndex = index(dragEl, options.draggable);
+
+        _dispatchEvent({
+          sortable: _this,
+          name: 'change',
+          toEl: el,
+          newIndex: newIndex,
+          newDraggableIndex: newDraggableIndex,
+          originalEvent: evt
+        });
+      }
+
+      if (evt.preventDefault !== void 0) {
+        evt.cancelable && evt.preventDefault();
+      }
+
+      target = closest(target, options.draggable, el, true);
+      dragOverEvent('dragOver');
+      if (Sortable.eventCanceled) return completedFired;
+
+      if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
+        return completed(false);
+      }
+
+      ignoreNextClick = false;
+
+      if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
+      : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
+        vertical = this._getDirection(evt, target) === 'vertical';
+        dragRect = getRect(dragEl);
+        dragOverEvent('dragOverValid');
+        if (Sortable.eventCanceled) return completedFired;
+
+        if (revert) {
+          parentEl = rootEl; // actualization
+
+          capture();
+
+          this._hideClone();
+
+          dragOverEvent('revert');
+
+          if (!Sortable.eventCanceled) {
+            if (nextEl) {
+              rootEl.insertBefore(dragEl, nextEl);
+            } else {
+              rootEl.appendChild(dragEl);
+            }
+          }
+
+          return completed(true);
+        }
+
+        var elLastChild = lastChild(el, options.draggable);
+
+        if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
+          // If already at end of list: Do not insert
+          if (elLastChild === dragEl) {
+            return completed(false);
+          } // assign target only if condition is true
+
+
+          if (elLastChild && el === evt.target) {
+            target = elLastChild;
+          }
+
+          if (target) {
+            targetRect = getRect(target);
+          }
+
+          if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
+            capture();
+            el.appendChild(dragEl);
+            parentEl = el; // actualization
+
+            changed();
+            return completed(true);
+          }
+        } else if (target.parentNode === el) {
+          targetRect = getRect(target);
+          var direction = 0,
+              targetBeforeFirstSwap,
+              differentLevel = dragEl.parentNode !== el,
+              differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
+              side1 = vertical ? 'top' : 'left',
+              scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
+              scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
+
+          if (lastTarget !== target) {
+            targetBeforeFirstSwap = targetRect[side1];
+            pastFirstInvertThresh = false;
+            isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
+          }
+
+          direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
+          var sibling;
+
+          if (direction !== 0) {
+            // Check if target is beside dragEl in respective direction (ignoring hidden elements)
+            var dragIndex = index(dragEl);
+
+            do {
+              dragIndex -= direction;
+              sibling = parentEl.children[dragIndex];
+            } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
+          } // If dragEl is already beside target: Do not insert
+
+
+          if (direction === 0 || sibling === target) {
+            return completed(false);
+          }
+
+          lastTarget = target;
+          lastDirection = direction;
+          var nextSibling = target.nextElementSibling,
+              after = false;
+          after = direction === 1;
+
+          var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
+
+          if (moveVector !== false) {
+            if (moveVector === 1 || moveVector === -1) {
+              after = moveVector === 1;
+            }
+
+            _silent = true;
+            setTimeout(_unsilent, 30);
+            capture();
+
+            if (after && !nextSibling) {
+              el.appendChild(dragEl);
+            } else {
+              target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
+            } // Undo chrome's scroll adjustment (has no effect on other browsers)
+
+
+            if (scrolledPastTop) {
+              scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
+            }
+
+            parentEl = dragEl.parentNode; // actualization
+            // must be done before animation
+
+            if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
+              targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
+            }
+
+            changed();
+            return completed(true);
+          }
+        }
+
+        if (el.contains(dragEl)) {
+          return completed(false);
+        }
+      }
+
+      return false;
+    },
+    _ignoreWhileAnimating: null,
+    _offMoveEvents: function _offMoveEvents() {
+      off(document, 'mousemove', this._onTouchMove);
+      off(document, 'touchmove', this._onTouchMove);
+      off(document, 'pointermove', this._onTouchMove);
+      off(document, 'dragover', nearestEmptyInsertDetectEvent);
+      off(document, 'mousemove', nearestEmptyInsertDetectEvent);
+      off(document, 'touchmove', nearestEmptyInsertDetectEvent);
+    },
+    _offUpEvents: function _offUpEvents() {
+      var ownerDocument = this.el.ownerDocument;
+      off(ownerDocument, 'mouseup', this._onDrop);
+      off(ownerDocument, 'touchend', this._onDrop);
+      off(ownerDocument, 'pointerup', this._onDrop);
+      off(ownerDocument, 'touchcancel', this._onDrop);
+      off(document, 'selectstart', this);
+    },
+    _onDrop: function _onDrop(
+    /**Event*/
+    evt) {
+      var el = this.el,
+          options = this.options; // Get the index of the dragged element within its parent
+
+      newIndex = index(dragEl);
+      newDraggableIndex = index(dragEl, options.draggable);
+      pluginEvent('drop', this, {
+        evt: evt
+      });
+      parentEl = dragEl && dragEl.parentNode; // Get again after plugin event
+
+      newIndex = index(dragEl);
+      newDraggableIndex = index(dragEl, options.draggable);
+
+      if (Sortable.eventCanceled) {
+        this._nulling();
+
+        return;
+      }
+
+      awaitingDragStarted = false;
+      isCircumstantialInvert = false;
+      pastFirstInvertThresh = false;
+      clearInterval(this._loopId);
+      clearTimeout(this._dragStartTimer);
+
+      _cancelNextTick(this.cloneId);
+
+      _cancelNextTick(this._dragStartId); // Unbind events
+
+
+      if (this.nativeDraggable) {
+        off(document, 'drop', this);
+        off(el, 'dragstart', this._onDragStart);
+      }
+
+      this._offMoveEvents();
+
+      this._offUpEvents();
+
+      if (Safari) {
+        css(document.body, 'user-select', '');
+      }
+
+      css(dragEl, 'transform', '');
+
+      if (evt) {
+        if (moved) {
+          evt.cancelable && evt.preventDefault();
+          !options.dropBubble && evt.stopPropagation();
+        }
+
+        ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
+
+        if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+          // Remove clone(s)
+          cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
+        }
+
+        if (dragEl) {
+          if (this.nativeDraggable) {
+            off(dragEl, 'dragend', this);
+          }
+
+          _disableDraggable(dragEl);
+
+          dragEl.style['will-change'] = ''; // Remove classes
+          // ghostClass is added in dragStarted
+
+          if (moved && !awaitingDragStarted) {
+            toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
+          }
+
+          toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
+
+          _dispatchEvent({
+            sortable: this,
+            name: 'unchoose',
+            toEl: parentEl,
+            newIndex: null,
+            newDraggableIndex: null,
+            originalEvent: evt
+          });
+
+          if (rootEl !== parentEl) {
+            if (newIndex >= 0) {
+              // Add event
+              _dispatchEvent({
+                rootEl: parentEl,
+                name: 'add',
+                toEl: parentEl,
+                fromEl: rootEl,
+                originalEvent: evt
+              }); // Remove event
+
+
+              _dispatchEvent({
+                sortable: this,
+                name: 'remove',
+                toEl: parentEl,
+                originalEvent: evt
+              }); // drag from one list and drop into another
+
+
+              _dispatchEvent({
+                rootEl: parentEl,
+                name: 'sort',
+                toEl: parentEl,
+                fromEl: rootEl,
+                originalEvent: evt
+              });
+
+              _dispatchEvent({
+                sortable: this,
+                name: 'sort',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+            }
+
+            putSortable && putSortable.save();
+          } else {
+            if (newIndex !== oldIndex) {
+              if (newIndex >= 0) {
+                // drag & drop within the same list
+                _dispatchEvent({
+                  sortable: this,
+                  name: 'update',
+                  toEl: parentEl,
+                  originalEvent: evt
+                });
+
+                _dispatchEvent({
+                  sortable: this,
+                  name: 'sort',
+                  toEl: parentEl,
+                  originalEvent: evt
+                });
+              }
+            }
+          }
+
+          if (Sortable.active) {
+            /* jshint eqnull:true */
+            if (newIndex == null || newIndex === -1) {
+              newIndex = oldIndex;
+              newDraggableIndex = oldDraggableIndex;
+            }
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'end',
+              toEl: parentEl,
+              originalEvent: evt
+            }); // Save sorting
+
+
+            this.save();
+          }
+        }
+      }
+
+      this._nulling();
+    },
+    _nulling: function _nulling() {
+      pluginEvent('nulling', this);
+      rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
+      savedInputChecked.forEach(function (el) {
+        el.checked = true;
+      });
+      savedInputChecked.length = lastDx = lastDy = 0;
+    },
+    handleEvent: function handleEvent(
+    /**Event*/
+    evt) {
+      switch (evt.type) {
+        case 'drop':
+        case 'dragend':
+          this._onDrop(evt);
+
+          break;
+
+        case 'dragenter':
+        case 'dragover':
+          if (dragEl) {
+            this._onDragOver(evt);
+
+            _globalDragOver(evt);
+          }
+
+          break;
+
+        case 'selectstart':
+          evt.preventDefault();
+          break;
+      }
+    },
+
+    /**
+     * Serializes the item into an array of string.
+     * @returns {String[]}
+     */
+    toArray: function toArray() {
+      var order = [],
+          el,
+          children = this.el.children,
+          i = 0,
+          n = children.length,
+          options = this.options;
+
+      for (; i < n; i++) {
+        el = children[i];
+
+        if (closest(el, options.draggable, this.el, false)) {
+          order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
+        }
+      }
+
+      return order;
+    },
+
+    /**
+     * Sorts the elements according to the array.
+     * @param  {String[]}  order  order of the items
+     */
+    sort: function sort(order) {
+      var items = {},
+          rootEl = this.el;
+      this.toArray().forEach(function (id, i) {
+        var el = rootEl.children[i];
+
+        if (closest(el, this.options.draggable, rootEl, false)) {
+          items[id] = el;
+        }
+      }, this);
+      order.forEach(function (id) {
+        if (items[id]) {
+          rootEl.removeChild(items[id]);
+          rootEl.appendChild(items[id]);
+        }
+      });
+    },
+
+    /**
+     * Save the current sorting
+     */
+    save: function save() {
+      var store = this.options.store;
+      store && store.set && store.set(this);
+    },
+
+    /**
+     * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+     * @param   {HTMLElement}  el
+     * @param   {String}       [selector]  default: `options.draggable`
+     * @returns {HTMLElement|null}
+     */
+    closest: function closest$1(el, selector) {
+      return closest(el, selector || this.options.draggable, this.el, false);
+    },
+
+    /**
+     * Set/get option
+     * @param   {string} name
+     * @param   {*}      [value]
+     * @returns {*}
+     */
+    option: function option(name, value) {
+      var options = this.options;
+
+      if (value === void 0) {
+        return options[name];
+      } else {
+        var modifiedValue = PluginManager.modifyOption(this, name, value);
+
+        if (typeof modifiedValue !== 'undefined') {
+          options[name] = modifiedValue;
+        } else {
+          options[name] = value;
+        }
+
+        if (name === 'group') {
+          _prepareGroup(options);
+        }
+      }
+    },
+
+    /**
+     * Destroy
+     */
+    destroy: function destroy() {
+      pluginEvent('destroy', this);
+      var el = this.el;
+      el[expando] = null;
+      off(el, 'mousedown', this._onTapStart);
+      off(el, 'touchstart', this._onTapStart);
+      off(el, 'pointerdown', this._onTapStart);
+
+      if (this.nativeDraggable) {
+        off(el, 'dragover', this);
+        off(el, 'dragenter', this);
+      } // Remove draggable attributes
+
+
+      Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
+        el.removeAttribute('draggable');
+      });
+
+      this._onDrop();
+
+      this._disableDelayedDragEvents();
+
+      sortables.splice(sortables.indexOf(this.el), 1);
+      this.el = el = null;
+    },
+    _hideClone: function _hideClone() {
+      if (!cloneHidden) {
+        pluginEvent('hideClone', this);
+        if (Sortable.eventCanceled) return;
+        css(cloneEl, 'display', 'none');
+
+        if (this.options.removeCloneOnHide && cloneEl.parentNode) {
+          cloneEl.parentNode.removeChild(cloneEl);
+        }
+
+        cloneHidden = true;
+      }
+    },
+    _showClone: function _showClone(putSortable) {
+      if (putSortable.lastPutMode !== 'clone') {
+        this._hideClone();
+
+        return;
+      }
+
+      if (cloneHidden) {
+        pluginEvent('showClone', this);
+        if (Sortable.eventCanceled) return; // show clone at dragEl or original position
+
+        if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
+          rootEl.insertBefore(cloneEl, dragEl);
+        } else if (nextEl) {
+          rootEl.insertBefore(cloneEl, nextEl);
+        } else {
+          rootEl.appendChild(cloneEl);
+        }
+
+        if (this.options.group.revertClone) {
+          this.animate(dragEl, cloneEl);
+        }
+
+        css(cloneEl, 'display', '');
+        cloneHidden = false;
+      }
+    }
+  };
+
+  function _globalDragOver(
+  /**Event*/
+  evt) {
+    if (evt.dataTransfer) {
+      evt.dataTransfer.dropEffect = 'move';
+    }
+
+    evt.cancelable && evt.preventDefault();
+  }
+
+  function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
+    var evt,
+        sortable = fromEl[expando],
+        onMoveFn = sortable.options.onMove,
+        retVal; // Support for new CustomEvent feature
+
+    if (window.CustomEvent && !IE11OrLess && !Edge) {
+      evt = new CustomEvent('move', {
+        bubbles: true,
+        cancelable: true
+      });
+    } else {
+      evt = document.createEvent('Event');
+      evt.initEvent('move', true, true);
+    }
+
+    evt.to = toEl;
+    evt.from = fromEl;
+    evt.dragged = dragEl;
+    evt.draggedRect = dragRect;
+    evt.related = targetEl || toEl;
+    evt.relatedRect = targetRect || getRect(toEl);
+    evt.willInsertAfter = willInsertAfter;
+    evt.originalEvent = originalEvent;
+    fromEl.dispatchEvent(evt);
+
+    if (onMoveFn) {
+      retVal = onMoveFn.call(sortable, evt, originalEvent);
+    }
+
+    return retVal;
+  }
+
+  function _disableDraggable(el) {
+    el.draggable = false;
+  }
+
+  function _unsilent() {
+    _silent = false;
+  }
+
+  function _ghostIsLast(evt, vertical, sortable) {
+    var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
+    var spacer = 10;
+    return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
+  }
+
+  function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
+    var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
+        targetLength = vertical ? targetRect.height : targetRect.width,
+        targetS1 = vertical ? targetRect.top : targetRect.left,
+        targetS2 = vertical ? targetRect.bottom : targetRect.right,
+        invert = false;
+
+    if (!invertSwap) {
+      // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
+      if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
+        // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
+        // check if past first invert threshold on side opposite of lastDirection
+        if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
+          // past first invert threshold, do not restrict inverted threshold to dragEl shadow
+          pastFirstInvertThresh = true;
+        }
+
+        if (!pastFirstInvertThresh) {
+          // dragEl shadow (target move distance shadow)
+          if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
+          : mouseOnAxis > targetS2 - targetMoveDistance) {
+            return -lastDirection;
+          }
+        } else {
+          invert = true;
+        }
+      } else {
+        // Regular
+        if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
+          return _getInsertDirection(target);
+        }
+      }
+    }
+
+    invert = invert || invertSwap;
+
+    if (invert) {
+      // Invert of regular
+      if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
+        return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
+      }
+    }
+
+    return 0;
+  }
+  /**
+   * Gets the direction dragEl must be swapped relative to target in order to make it
+   * seem that dragEl has been "inserted" into that element's position
+   * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
+   * @return {Number}                   Direction dragEl must be swapped
+   */
+
+
+  function _getInsertDirection(target) {
+    if (index(dragEl) < index(target)) {
+      return 1;
+    } else {
+      return -1;
+    }
+  }
+  /**
+   * Generate id
+   * @param   {HTMLElement} el
+   * @returns {String}
+   * @private
+   */
+
+
+  function _generateId(el) {
+    var str = el.tagName + el.className + el.src + el.href + el.textContent,
+        i = str.length,
+        sum = 0;
+
+    while (i--) {
+      sum += str.charCodeAt(i);
+    }
+
+    return sum.toString(36);
+  }
+
+  function _saveInputCheckedState(root) {
+    savedInputChecked.length = 0;
+    var inputs = root.getElementsByTagName('input');
+    var idx = inputs.length;
+
+    while (idx--) {
+      var el = inputs[idx];
+      el.checked && savedInputChecked.push(el);
+    }
+  }
+
+  function _nextTick(fn) {
+    return setTimeout(fn, 0);
+  }
+
+  function _cancelNextTick(id) {
+    return clearTimeout(id);
+  } // Fixed #973:
+
+
+  if (documentExists) {
+    on(document, 'touchmove', function (evt) {
+      if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
+        evt.preventDefault();
+      }
+    });
+  } // Export utils
+
+
+  Sortable.utils = {
+    on: on,
+    off: off,
+    css: css,
+    find: find,
+    is: function is(el, selector) {
+      return !!closest(el, selector, el, false);
+    },
+    extend: extend,
+    throttle: throttle,
+    closest: closest,
+    toggleClass: toggleClass,
+    clone: clone,
+    index: index,
+    nextTick: _nextTick,
+    cancelNextTick: _cancelNextTick,
+    detectDirection: _detectDirection,
+    getChild: getChild
+  };
+  /**
+   * Get the Sortable instance of an element
+   * @param  {HTMLElement} element The element
+   * @return {Sortable|undefined}         The instance of Sortable
+   */
+
+  Sortable.get = function (element) {
+    return element[expando];
+  };
+  /**
+   * Mount a plugin to Sortable
+   * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
+   */
+
+
+  Sortable.mount = function () {
+    for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
+      plugins[_key] = arguments[_key];
+    }
+
+    if (plugins[0].constructor === Array) plugins = plugins[0];
+    plugins.forEach(function (plugin) {
+      if (!plugin.prototype || !plugin.prototype.constructor) {
+        throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
+      }
+
+      if (plugin.utils) Sortable.utils = _objectSpread({}, Sortable.utils, plugin.utils);
+      PluginManager.mount(plugin);
+    });
+  };
+  /**
+   * Create sortable instance
+   * @param {HTMLElement}  el
+   * @param {Object}      [options]
+   */
+
+
+  Sortable.create = function (el, options) {
+    return new Sortable(el, options);
+  }; // Export
+
+
+  Sortable.version = version;
+
+  var autoScrolls = [],
+      scrollEl,
+      scrollRootEl,
+      scrolling = false,
+      lastAutoScrollX,
+      lastAutoScrollY,
+      touchEvt$1,
+      pointerElemChangedInterval;
+
+  function AutoScrollPlugin() {
+    function AutoScroll() {
+      this.defaults = {
+        scroll: true,
+        scrollSensitivity: 30,
+        scrollSpeed: 10,
+        bubbleScroll: true
+      }; // Bind all private methods
+
+      for (var fn in this) {
+        if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+          this[fn] = this[fn].bind(this);
+        }
+      }
+    }
+
+    AutoScroll.prototype = {
+      dragStarted: function dragStarted(_ref) {
+        var originalEvent = _ref.originalEvent;
+
+        if (this.sortable.nativeDraggable) {
+          on(document, 'dragover', this._handleAutoScroll);
+        } else {
+          if (this.options.supportPointer) {
+            on(document, 'pointermove', this._handleFallbackAutoScroll);
+          } else if (originalEvent.touches) {
+            on(document, 'touchmove', this._handleFallbackAutoScroll);
+          } else {
+            on(document, 'mousemove', this._handleFallbackAutoScroll);
+          }
+        }
+      },
+      dragOverCompleted: function dragOverCompleted(_ref2) {
+        var originalEvent = _ref2.originalEvent;
+
+        // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
+        if (!this.options.dragOverBubble && !originalEvent.rootEl) {
+          this._handleAutoScroll(originalEvent);
+        }
+      },
+      drop: function drop() {
+        if (this.sortable.nativeDraggable) {
+          off(document, 'dragover', this._handleAutoScroll);
+        } else {
+          off(document, 'pointermove', this._handleFallbackAutoScroll);
+          off(document, 'touchmove', this._handleFallbackAutoScroll);
+          off(document, 'mousemove', this._handleFallbackAutoScroll);
+        }
+
+        clearPointerElemChangedInterval();
+        clearAutoScrolls();
+        cancelThrottle();
+      },
+      nulling: function nulling() {
+        touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
+        autoScrolls.length = 0;
+      },
+      _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
+        this._handleAutoScroll(evt, true);
+      },
+      _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
+        var _this = this;
+
+        var x = (evt.touches ? evt.touches[0] : evt).clientX,
+            y = (evt.touches ? evt.touches[0] : evt).clientY,
+            elem = document.elementFromPoint(x, y);
+        touchEvt$1 = evt; // IE does not seem to have native autoscroll,
+        // Edge's autoscroll seems too conditional,
+        // MACOS Safari does not have autoscroll,
+        // Firefox and Chrome are good
+
+        if (fallback || Edge || IE11OrLess || Safari) {
+          autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
+
+          var ogElemScroller = getParentAutoScrollElement(elem, true);
+
+          if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
+            pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
+
+            pointerElemChangedInterval = setInterval(function () {
+              var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
+
+              if (newElem !== ogElemScroller) {
+                ogElemScroller = newElem;
+                clearAutoScrolls();
+              }
+
+              autoScroll(evt, _this.options, newElem, fallback);
+            }, 10);
+            lastAutoScrollX = x;
+            lastAutoScrollY = y;
+          }
+        } else {
+          // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
+          if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
+            clearAutoScrolls();
+            return;
+          }
+
+          autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
+        }
+      }
+    };
+    return _extends(AutoScroll, {
+      pluginName: 'scroll',
+      initializeByDefault: true
+    });
+  }
+
+  function clearAutoScrolls() {
+    autoScrolls.forEach(function (autoScroll) {
+      clearInterval(autoScroll.pid);
+    });
+    autoScrolls = [];
+  }
+
+  function clearPointerElemChangedInterval() {
+    clearInterval(pointerElemChangedInterval);
+  }
+
+  var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
+    // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+    if (!options.scroll) return;
+    var x = (evt.touches ? evt.touches[0] : evt).clientX,
+        y = (evt.touches ? evt.touches[0] : evt).clientY,
+        sens = options.scrollSensitivity,
+        speed = options.scrollSpeed,
+        winScroller = getWindowScrollingElement();
+    var scrollThisInstance = false,
+        scrollCustomFn; // New scroll root, set scrollEl
+
+    if (scrollRootEl !== rootEl) {
+      scrollRootEl = rootEl;
+      clearAutoScrolls();
+      scrollEl = options.scroll;
+      scrollCustomFn = options.scrollFn;
+
+      if (scrollEl === true) {
+        scrollEl = getParentAutoScrollElement(rootEl, true);
+      }
+    }
+
+    var layersOut = 0;
+    var currentParent = scrollEl;
+
+    do {
+      var el = currentParent,
+          rect = getRect(el),
+          top = rect.top,
+          bottom = rect.bottom,
+          left = rect.left,
+          right = rect.right,
+          width = rect.width,
+          height = rect.height,
+          canScrollX = void 0,
+          canScrollY = void 0,
+          scrollWidth = el.scrollWidth,
+          scrollHeight = el.scrollHeight,
+          elCSS = css(el),
+          scrollPosX = el.scrollLeft,
+          scrollPosY = el.scrollTop;
+
+      if (el === winScroller) {
+        canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
+        canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
+      } else {
+        canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
+        canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
+      }
+
+      var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
+      var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
+
+      if (!autoScrolls[layersOut]) {
+        for (var i = 0; i <= layersOut; i++) {
+          if (!autoScrolls[i]) {
+            autoScrolls[i] = {};
+          }
+        }
+      }
+
+      if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
+        autoScrolls[layersOut].el = el;
+        autoScrolls[layersOut].vx = vx;
+        autoScrolls[layersOut].vy = vy;
+        clearInterval(autoScrolls[layersOut].pid);
+
+        if (vx != 0 || vy != 0) {
+          scrollThisInstance = true;
+          /* jshint loopfunc:true */
+
+          autoScrolls[layersOut].pid = setInterval(function () {
+            // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
+            if (isFallback && this.layer === 0) {
+              Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
+
+            }
+
+            var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
+            var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
+
+            if (typeof scrollCustomFn === 'function') {
+              if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
+                return;
+              }
+            }
+
+            scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
+          }.bind({
+            layer: layersOut
+          }), 24);
+        }
+      }
+
+      layersOut++;
+    } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
+
+    scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
+  }, 30);
+
+  var drop = function drop(_ref) {
+    var originalEvent = _ref.originalEvent,
+        putSortable = _ref.putSortable,
+        dragEl = _ref.dragEl,
+        activeSortable = _ref.activeSortable,
+        dispatchSortableEvent = _ref.dispatchSortableEvent,
+        hideGhostForTarget = _ref.hideGhostForTarget,
+        unhideGhostForTarget = _ref.unhideGhostForTarget;
+    if (!originalEvent) return;
+    var toSortable = putSortable || activeSortable;
+    hideGhostForTarget();
+    var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
+    var target = document.elementFromPoint(touch.clientX, touch.clientY);
+    unhideGhostForTarget();
+
+    if (toSortable && !toSortable.el.contains(target)) {
+      dispatchSortableEvent('spill');
+      this.onSpill({
+        dragEl: dragEl,
+        putSortable: putSortable
+      });
+    }
+  };
+
+  function Revert() {}
+
+  Revert.prototype = {
+    startIndex: null,
+    dragStart: function dragStart(_ref2) {
+      var oldDraggableIndex = _ref2.oldDraggableIndex;
+      this.startIndex = oldDraggableIndex;
+    },
+    onSpill: function onSpill(_ref3) {
+      var dragEl = _ref3.dragEl,
+          putSortable = _ref3.putSortable;
+      this.sortable.captureAnimationState();
+
+      if (putSortable) {
+        putSortable.captureAnimationState();
+      }
+
+      var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
+
+      if (nextSibling) {
+        this.sortable.el.insertBefore(dragEl, nextSibling);
+      } else {
+        this.sortable.el.appendChild(dragEl);
+      }
+
+      this.sortable.animateAll();
+
+      if (putSortable) {
+        putSortable.animateAll();
+      }
+    },
+    drop: drop
+  };
+
+  _extends(Revert, {
+    pluginName: 'revertOnSpill'
+  });
+
+  function Remove() {}
+
+  Remove.prototype = {
+    onSpill: function onSpill(_ref4) {
+      var dragEl = _ref4.dragEl,
+          putSortable = _ref4.putSortable;
+      var parentSortable = putSortable || this.sortable;
+      parentSortable.captureAnimationState();
+      dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
+      parentSortable.animateAll();
+    },
+    drop: drop
+  };
+
+  _extends(Remove, {
+    pluginName: 'removeOnSpill'
+  });
+
+  var lastSwapEl;
+
+  function SwapPlugin() {
+    function Swap() {
+      this.defaults = {
+        swapClass: 'sortable-swap-highlight'
+      };
+    }
+
+    Swap.prototype = {
+      dragStart: function dragStart(_ref) {
+        var dragEl = _ref.dragEl;
+        lastSwapEl = dragEl;
+      },
+      dragOverValid: function dragOverValid(_ref2) {
+        var completed = _ref2.completed,
+            target = _ref2.target,
+            onMove = _ref2.onMove,
+            activeSortable = _ref2.activeSortable,
+            changed = _ref2.changed,
+            cancel = _ref2.cancel;
+        if (!activeSortable.options.swap) return;
+        var el = this.sortable.el,
+            options = this.options;
+
+        if (target && target !== el) {
+          var prevSwapEl = lastSwapEl;
+
+          if (onMove(target) !== false) {
+            toggleClass(target, options.swapClass, true);
+            lastSwapEl = target;
+          } else {
+            lastSwapEl = null;
+          }
+
+          if (prevSwapEl && prevSwapEl !== lastSwapEl) {
+            toggleClass(prevSwapEl, options.swapClass, false);
+          }
+        }
+
+        changed();
+        completed(true);
+        cancel();
+      },
+      drop: function drop(_ref3) {
+        var activeSortable = _ref3.activeSortable,
+            putSortable = _ref3.putSortable,
+            dragEl = _ref3.dragEl;
+        var toSortable = putSortable || this.sortable;
+        var options = this.options;
+        lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
+
+        if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
+          if (dragEl !== lastSwapEl) {
+            toSortable.captureAnimationState();
+            if (toSortable !== activeSortable) activeSortable.captureAnimationState();
+            swapNodes(dragEl, lastSwapEl);
+            toSortable.animateAll();
+            if (toSortable !== activeSortable) activeSortable.animateAll();
+          }
+        }
+      },
+      nulling: function nulling() {
+        lastSwapEl = null;
+      }
+    };
+    return _extends(Swap, {
+      pluginName: 'swap',
+      eventProperties: function eventProperties() {
+        return {
+          swapItem: lastSwapEl
+        };
+      }
+    });
+  }
+
+  function swapNodes(n1, n2) {
+    var p1 = n1.parentNode,
+        p2 = n2.parentNode,
+        i1,
+        i2;
+    if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
+    i1 = index(n1);
+    i2 = index(n2);
+
+    if (p1.isEqualNode(p2) && i1 < i2) {
+      i2++;
+    }
+
+    p1.insertBefore(n2, p1.children[i1]);
+    p2.insertBefore(n1, p2.children[i2]);
+  }
+
+  var multiDragElements = [],
+      multiDragClones = [],
+      lastMultiDragSelect,
+      // for selection with modifier key down (SHIFT)
+  multiDragSortable,
+      initialFolding = false,
+      // Initial multi-drag fold when drag started
+  folding = false,
+      // Folding any other time
+  dragStarted = false,
+      dragEl$1,
+      clonesFromRect,
+      clonesHidden;
+
+  function MultiDragPlugin() {
+    function MultiDrag(sortable) {
+      // Bind all private methods
+      for (var fn in this) {
+        if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+          this[fn] = this[fn].bind(this);
+        }
+      }
+
+      if (sortable.options.supportPointer) {
+        on(document, 'pointerup', this._deselectMultiDrag);
+      } else {
+        on(document, 'mouseup', this._deselectMultiDrag);
+        on(document, 'touchend', this._deselectMultiDrag);
+      }
+
+      on(document, 'keydown', this._checkKeyDown);
+      on(document, 'keyup', this._checkKeyUp);
+      this.defaults = {
+        selectedClass: 'sortable-selected',
+        multiDragKey: null,
+        setData: function setData(dataTransfer, dragEl) {
+          var data = '';
+
+          if (multiDragElements.length && multiDragSortable === sortable) {
+            multiDragElements.forEach(function (multiDragElement, i) {
+              data += (!i ? '' : ', ') + multiDragElement.textContent;
+            });
+          } else {
+            data = dragEl.textContent;
+          }
+
+          dataTransfer.setData('Text', data);
+        }
+      };
+    }
+
+    MultiDrag.prototype = {
+      multiDragKeyDown: false,
+      isMultiDrag: false,
+      delayStartGlobal: function delayStartGlobal(_ref) {
+        var dragged = _ref.dragEl;
+        dragEl$1 = dragged;
+      },
+      delayEnded: function delayEnded() {
+        this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
+      },
+      setupClone: function setupClone(_ref2) {
+        var sortable = _ref2.sortable,
+            cancel = _ref2.cancel;
+        if (!this.isMultiDrag) return;
+
+        for (var i = 0; i < multiDragElements.length; i++) {
+          multiDragClones.push(clone(multiDragElements[i]));
+          multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
+          multiDragClones[i].draggable = false;
+          multiDragClones[i].style['will-change'] = '';
+          toggleClass(multiDragClones[i], this.options.selectedClass, false);
+          multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
+        }
+
+        sortable._hideClone();
+
+        cancel();
+      },
+      clone: function clone(_ref3) {
+        var sortable = _ref3.sortable,
+            rootEl = _ref3.rootEl,
+            dispatchSortableEvent = _ref3.dispatchSortableEvent,
+            cancel = _ref3.cancel;
+        if (!this.isMultiDrag) return;
+
+        if (!this.options.removeCloneOnHide) {
+          if (multiDragElements.length && multiDragSortable === sortable) {
+            insertMultiDragClones(true, rootEl);
+            dispatchSortableEvent('clone');
+            cancel();
+          }
+        }
+      },
+      showClone: function showClone(_ref4) {
+        var cloneNowShown = _ref4.cloneNowShown,
+            rootEl = _ref4.rootEl,
+            cancel = _ref4.cancel;
+        if (!this.isMultiDrag) return;
+        insertMultiDragClones(false, rootEl);
+        multiDragClones.forEach(function (clone) {
+          css(clone, 'display', '');
+        });
+        cloneNowShown();
+        clonesHidden = false;
+        cancel();
+      },
+      hideClone: function hideClone(_ref5) {
+        var _this = this;
+
+        var sortable = _ref5.sortable,
+            cloneNowHidden = _ref5.cloneNowHidden,
+            cancel = _ref5.cancel;
+        if (!this.isMultiDrag) return;
+        multiDragClones.forEach(function (clone) {
+          css(clone, 'display', 'none');
+
+          if (_this.options.removeCloneOnHide && clone.parentNode) {
+            clone.parentNode.removeChild(clone);
+          }
+        });
+        cloneNowHidden();
+        clonesHidden = true;
+        cancel();
+      },
+      dragStartGlobal: function dragStartGlobal(_ref6) {
+        var sortable = _ref6.sortable;
+
+        if (!this.isMultiDrag && multiDragSortable) {
+          multiDragSortable.multiDrag._deselectMultiDrag();
+        }
+
+        multiDragElements.forEach(function (multiDragElement) {
+          multiDragElement.sortableIndex = index(multiDragElement);
+        }); // Sort multi-drag elements
+
+        multiDragElements = multiDragElements.sort(function (a, b) {
+          return a.sortableIndex - b.sortableIndex;
+        });
+        dragStarted = true;
+      },
+      dragStarted: function dragStarted(_ref7) {
+        var _this2 = this;
+
+        var sortable = _ref7.sortable;
+        if (!this.isMultiDrag) return;
+
+        if (this.options.sort) {
+          // Capture rects,
+          // hide multi drag elements (by positioning them absolute),
+          // set multi drag elements rects to dragRect,
+          // show multi drag elements,
+          // animate to rects,
+          // unset rects & remove from DOM
+          sortable.captureAnimationState();
+
+          if (this.options.animation) {
+            multiDragElements.forEach(function (multiDragElement) {
+              if (multiDragElement === dragEl$1) return;
+              css(multiDragElement, 'position', 'absolute');
+            });
+            var dragRect = getRect(dragEl$1, false, true, true);
+            multiDragElements.forEach(function (multiDragElement) {
+              if (multiDragElement === dragEl$1) return;
+              setRect(multiDragElement, dragRect);
+            });
+            folding = true;
+            initialFolding = true;
+          }
+        }
+
+        sortable.animateAll(function () {
+          folding = false;
+          initialFolding = false;
+
+          if (_this2.options.animation) {
+            multiDragElements.forEach(function (multiDragElement) {
+              unsetRect(multiDragElement);
+            });
+          } // Remove all auxiliary multidrag items from el, if sorting enabled
+
+
+          if (_this2.options.sort) {
+            removeMultiDragElements();
+          }
+        });
+      },
+      dragOver: function dragOver(_ref8) {
+        var target = _ref8.target,
+            completed = _ref8.completed,
+            cancel = _ref8.cancel;
+
+        if (folding && ~multiDragElements.indexOf(target)) {
+          completed(false);
+          cancel();
+        }
+      },
+      revert: function revert(_ref9) {
+        var fromSortable = _ref9.fromSortable,
+            rootEl = _ref9.rootEl,
+            sortable = _ref9.sortable,
+            dragRect = _ref9.dragRect;
+
+        if (multiDragElements.length > 1) {
+          // Setup unfold animation
+          multiDragElements.forEach(function (multiDragElement) {
+            sortable.addAnimationState({
+              target: multiDragElement,
+              rect: folding ? getRect(multiDragElement) : dragRect
+            });
+            unsetRect(multiDragElement);
+            multiDragElement.fromRect = dragRect;
+            fromSortable.removeAnimationState(multiDragElement);
+          });
+          folding = false;
+          insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
+        }
+      },
+      dragOverCompleted: function dragOverCompleted(_ref10) {
+        var sortable = _ref10.sortable,
+            isOwner = _ref10.isOwner,
+            insertion = _ref10.insertion,
+            activeSortable = _ref10.activeSortable,
+            parentEl = _ref10.parentEl,
+            putSortable = _ref10.putSortable;
+        var options = this.options;
+
+        if (insertion) {
+          // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+          if (isOwner) {
+            activeSortable._hideClone();
+          }
+
+          initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location
+
+          if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
+            // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
+            var dragRectAbsolute = getRect(dragEl$1, false, true, true);
+            multiDragElements.forEach(function (multiDragElement) {
+              if (multiDragElement === dragEl$1) return;
+              setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
+              // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
+
+              parentEl.appendChild(multiDragElement);
+            });
+            folding = true;
+          } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
+
+
+          if (!isOwner) {
+            // Only remove if not folding (folding will remove them anyways)
+            if (!folding) {
+              removeMultiDragElements();
+            }
+
+            if (multiDragElements.length > 1) {
+              var clonesHiddenBefore = clonesHidden;
+
+              activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden
+
+
+              if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
+                multiDragClones.forEach(function (clone) {
+                  activeSortable.addAnimationState({
+                    target: clone,
+                    rect: clonesFromRect
+                  });
+                  clone.fromRect = clonesFromRect;
+                  clone.thisAnimationDuration = null;
+                });
+              }
+            } else {
+              activeSortable._showClone(sortable);
+            }
+          }
+        }
+      },
+      dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
+        var dragRect = _ref11.dragRect,
+            isOwner = _ref11.isOwner,
+            activeSortable = _ref11.activeSortable;
+        multiDragElements.forEach(function (multiDragElement) {
+          multiDragElement.thisAnimationDuration = null;
+        });
+
+        if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
+          clonesFromRect = _extends({}, dragRect);
+          var dragMatrix = matrix(dragEl$1, true);
+          clonesFromRect.top -= dragMatrix.f;
+          clonesFromRect.left -= dragMatrix.e;
+        }
+      },
+      dragOverAnimationComplete: function dragOverAnimationComplete() {
+        if (folding) {
+          folding = false;
+          removeMultiDragElements();
+        }
+      },
+      drop: function drop(_ref12) {
+        var evt = _ref12.originalEvent,
+            rootEl = _ref12.rootEl,
+            parentEl = _ref12.parentEl,
+            sortable = _ref12.sortable,
+            dispatchSortableEvent = _ref12.dispatchSortableEvent,
+            oldIndex = _ref12.oldIndex,
+            putSortable = _ref12.putSortable;
+        var toSortable = putSortable || this.sortable;
+        if (!evt) return;
+        var options = this.options,
+            children = parentEl.children; // Multi-drag selection
+
+        if (!dragStarted) {
+          if (options.multiDragKey && !this.multiDragKeyDown) {
+            this._deselectMultiDrag();
+          }
+
+          toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
+
+          if (!~multiDragElements.indexOf(dragEl$1)) {
+            multiDragElements.push(dragEl$1);
+            dispatchEvent({
+              sortable: sortable,
+              rootEl: rootEl,
+              name: 'select',
+              targetEl: dragEl$1,
+              originalEvt: evt
+            }); // Modifier activated, select from last to dragEl
+
+            if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
+              var lastIndex = index(lastMultiDragSelect),
+                  currentIndex = index(dragEl$1);
+
+              if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
+                // Must include lastMultiDragSelect (select it), in case modified selection from no selection
+                // (but previous selection existed)
+                var n, i;
+
+                if (currentIndex > lastIndex) {
+                  i = lastIndex;
+                  n = currentIndex;
+                } else {
+                  i = currentIndex;
+                  n = lastIndex + 1;
+                }
+
+                for (; i < n; i++) {
+                  if (~multiDragElements.indexOf(children[i])) continue;
+                  toggleClass(children[i], options.selectedClass, true);
+                  multiDragElements.push(children[i]);
+                  dispatchEvent({
+                    sortable: sortable,
+                    rootEl: rootEl,
+                    name: 'select',
+                    targetEl: children[i],
+                    originalEvt: evt
+                  });
+                }
+              }
+            } else {
+              lastMultiDragSelect = dragEl$1;
+            }
+
+            multiDragSortable = toSortable;
+          } else {
+            multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
+            lastMultiDragSelect = null;
+            dispatchEvent({
+              sortable: sortable,
+              rootEl: rootEl,
+              name: 'deselect',
+              targetEl: dragEl$1,
+              originalEvt: evt
+            });
+          }
+        } // Multi-drag drop
+
+
+        if (dragStarted && this.isMultiDrag) {
+          // Do not "unfold" after around dragEl if reverted
+          if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
+            var dragRect = getRect(dragEl$1),
+                multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
+            if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
+            toSortable.captureAnimationState();
+
+            if (!initialFolding) {
+              if (options.animation) {
+                dragEl$1.fromRect = dragRect;
+                multiDragElements.forEach(function (multiDragElement) {
+                  multiDragElement.thisAnimationDuration = null;
+
+                  if (multiDragElement !== dragEl$1) {
+                    var rect = folding ? getRect(multiDragElement) : dragRect;
+                    multiDragElement.fromRect = rect; // Prepare unfold animation
+
+                    toSortable.addAnimationState({
+                      target: multiDragElement,
+                      rect: rect
+                    });
+                  }
+                });
+              } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
+              // properly they must all be removed
+
+
+              removeMultiDragElements();
+              multiDragElements.forEach(function (multiDragElement) {
+                if (children[multiDragIndex]) {
+                  parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
+                } else {
+                  parentEl.appendChild(multiDragElement);
+                }
+
+                multiDragIndex++;
+              }); // If initial folding is done, the elements may have changed position because they are now
+              // unfolding around dragEl, even though dragEl may not have his index changed, so update event
+              // must be fired here as Sortable will not.
+
+              if (oldIndex === index(dragEl$1)) {
+                var update = false;
+                multiDragElements.forEach(function (multiDragElement) {
+                  if (multiDragElement.sortableIndex !== index(multiDragElement)) {
+                    update = true;
+                    return;
+                  }
+                });
+
+                if (update) {
+                  dispatchSortableEvent('update');
+                }
+              }
+            } // Must be done after capturing individual rects (scroll bar)
+
+
+            multiDragElements.forEach(function (multiDragElement) {
+              unsetRect(multiDragElement);
+            });
+            toSortable.animateAll();
+          }
+
+          multiDragSortable = toSortable;
+        } // Remove clones if necessary
+
+
+        if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+          multiDragClones.forEach(function (clone) {
+            clone.parentNode && clone.parentNode.removeChild(clone);
+          });
+        }
+      },
+      nullingGlobal: function nullingGlobal() {
+        this.isMultiDrag = dragStarted = false;
+        multiDragClones.length = 0;
+      },
+      destroyGlobal: function destroyGlobal() {
+        this._deselectMultiDrag();
+
+        off(document, 'pointerup', this._deselectMultiDrag);
+        off(document, 'mouseup', this._deselectMultiDrag);
+        off(document, 'touchend', this._deselectMultiDrag);
+        off(document, 'keydown', this._checkKeyDown);
+        off(document, 'keyup', this._checkKeyUp);
+      },
+      _deselectMultiDrag: function _deselectMultiDrag(evt) {
+        if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable
+
+        if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable
+
+        if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click
+
+        if (evt && evt.button !== 0) return;
+
+        while (multiDragElements.length) {
+          var el = multiDragElements[0];
+          toggleClass(el, this.options.selectedClass, false);
+          multiDragElements.shift();
+          dispatchEvent({
+            sortable: this.sortable,
+            rootEl: this.sortable.el,
+            name: 'deselect',
+            targetEl: el,
+            originalEvt: evt
+          });
+        }
+      },
+      _checkKeyDown: function _checkKeyDown(evt) {
+        if (evt.key === this.options.multiDragKey) {
+          this.multiDragKeyDown = true;
+        }
+      },
+      _checkKeyUp: function _checkKeyUp(evt) {
+        if (evt.key === this.options.multiDragKey) {
+          this.multiDragKeyDown = false;
+        }
+      }
+    };
+    return _extends(MultiDrag, {
+      // Static methods & properties
+      pluginName: 'multiDrag',
+      utils: {
+        /**
+         * Selects the provided multi-drag item
+         * @param  {HTMLElement} el    The element to be selected
+         */
+        select: function select(el) {
+          var sortable = el.parentNode[expando];
+          if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
+
+          if (multiDragSortable && multiDragSortable !== sortable) {
+            multiDragSortable.multiDrag._deselectMultiDrag();
+
+            multiDragSortable = sortable;
+          }
+
+          toggleClass(el, sortable.options.selectedClass, true);
+          multiDragElements.push(el);
+        },
+
+        /**
+         * Deselects the provided multi-drag item
+         * @param  {HTMLElement} el    The element to be deselected
+         */
+        deselect: function deselect(el) {
+          var sortable = el.parentNode[expando],
+              index = multiDragElements.indexOf(el);
+          if (!sortable || !sortable.options.multiDrag || !~index) return;
+          toggleClass(el, sortable.options.selectedClass, false);
+          multiDragElements.splice(index, 1);
+        }
+      },
+      eventProperties: function eventProperties() {
+        var _this3 = this;
+
+        var oldIndicies = [],
+            newIndicies = [];
+        multiDragElements.forEach(function (multiDragElement) {
+          oldIndicies.push({
+            multiDragElement: multiDragElement,
+            index: multiDragElement.sortableIndex
+          }); // multiDragElements will already be sorted if folding
+
+          var newIndex;
+
+          if (folding && multiDragElement !== dragEl$1) {
+            newIndex = -1;
+          } else if (folding) {
+            newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
+          } else {
+            newIndex = index(multiDragElement);
+          }
+
+          newIndicies.push({
+            multiDragElement: multiDragElement,
+            index: newIndex
+          });
+        });
+        return {
+          items: _toConsumableArray(multiDragElements),
+          clones: [].concat(multiDragClones),
+          oldIndicies: oldIndicies,
+          newIndicies: newIndicies
+        };
+      },
+      optionListeners: {
+        multiDragKey: function multiDragKey(key) {
+          key = key.toLowerCase();
+
+          if (key === 'ctrl') {
+            key = 'Control';
+          } else if (key.length > 1) {
+            key = key.charAt(0).toUpperCase() + key.substr(1);
+          }
+
+          return key;
+        }
+      }
+    });
+  }
+
+  function insertMultiDragElements(clonesInserted, rootEl) {
+    multiDragElements.forEach(function (multiDragElement, i) {
+      var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
+
+      if (target) {
+        rootEl.insertBefore(multiDragElement, target);
+      } else {
+        rootEl.appendChild(multiDragElement);
+      }
+    });
+  }
+  /**
+   * Insert multi-drag clones
+   * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
+   * @param  {HTMLElement} rootEl
+   */
+
+
+  function insertMultiDragClones(elementsInserted, rootEl) {
+    multiDragClones.forEach(function (clone, i) {
+      var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
+
+      if (target) {
+        rootEl.insertBefore(clone, target);
+      } else {
+        rootEl.appendChild(clone);
+      }
+    });
+  }
+
+  function removeMultiDragElements() {
+    multiDragElements.forEach(function (multiDragElement) {
+      if (multiDragElement === dragEl$1) return;
+      multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
+    });
+  }
+
+  Sortable.mount(new AutoScrollPlugin());
+  Sortable.mount(Remove, Revert);
+
+  Sortable.mount(new SwapPlugin());
+  Sortable.mount(new MultiDragPlugin());
+
+  return Sortable;
+
+}));

File diff suppressed because it is too large
+ 1 - 0
public/assets/libs/Sortable/Sortable.min.js


+ 27 - 0
public/assets/libs/Sortable/babel.config.js

@@ -0,0 +1,27 @@
+module.exports = function(api) {
+	api.cache(true);
+
+	let presets;
+
+	if (process.env.NODE_ENV === 'es') {
+		presets = [
+			[
+				"@babel/preset-env",
+				{
+					"modules": false
+				}
+			]
+		];
+	} else if (process.env.NODE_ENV === 'umd') {
+		presets = [
+			[
+				"@babel/preset-env"
+			]
+		];
+	}
+
+	return {
+		plugins: ['@babel/plugin-transform-object-assign'],
+		presets
+	};
+};

+ 30 - 0
public/assets/libs/Sortable/bower.json

@@ -0,0 +1,30 @@
+{
+  "name": "Sortable",
+  "main": [
+    "Sortable.js"
+  ],
+  "homepage": "http://SortableJS.github.io/Sortable/",
+  "authors": [
+    "RubaXa <ibnRubaXa@gmail.com>",
+    "owenm <owen23355@gmail.com>"
+  ],
+  "description": "JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.",
+  "keywords": [
+    "sortable",
+    "reorder",
+    "list",
+    "html5",
+    "drag",
+    "and",
+    "drop",
+    "dnd",
+    "web-components"
+  ],
+  "license": "MIT",
+  "ignore": [
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ]
+}

+ 8 - 0
public/assets/libs/Sortable/entry/entry-complete.js

@@ -0,0 +1,8 @@
+import Sortable from './entry-defaults.js';
+import Swap from '../plugins/Swap';
+import MultiDrag from '../plugins/MultiDrag';
+
+Sortable.mount(new Swap());
+Sortable.mount(new MultiDrag());
+
+export default Sortable;

+ 19 - 0
public/assets/libs/Sortable/entry/entry-core.js

@@ -0,0 +1,19 @@
+import Sortable from '../src/Sortable.js';
+import AutoScroll from '../plugins/AutoScroll';
+import OnSpill from '../plugins/OnSpill';
+import Swap from '../plugins/Swap';
+import MultiDrag from '../plugins/MultiDrag';
+
+export default Sortable;
+
+export {
+	Sortable,
+
+	// Default
+	AutoScroll,
+	OnSpill,
+
+	// Extra
+	Swap,
+	MultiDrag
+};

+ 19 - 0
public/assets/libs/Sortable/entry/entry-defaults.js

@@ -0,0 +1,19 @@
+import Sortable from '../src/Sortable.js';
+import AutoScroll from '../plugins/AutoScroll';
+import { RemoveOnSpill, RevertOnSpill } from '../plugins/OnSpill';
+// Extra
+import Swap from '../plugins/Swap';
+import MultiDrag from '../plugins/MultiDrag';
+
+Sortable.mount(new AutoScroll());
+Sortable.mount(RemoveOnSpill, RevertOnSpill);
+
+export default Sortable;
+
+export {
+	Sortable,
+
+	// Extra
+	Swap,
+	MultiDrag
+};

+ 459 - 0
public/assets/libs/Sortable/index.html

@@ -0,0 +1,459 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<link rel="icon" type="image/png" href="st/og-image.png">
+	<title>SortableJS</title>
+	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
+	<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
+	<link rel="stylesheet" type="text/css" href="st/theme.css">
+
+	<meta charset="utf-8"/>
+	<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
+	<meta property="og:image" content="/st/og-image.png"/>
+	<meta name="keywords" content="sortable, reorder, list, javascript, html5, drag and drop, dnd, animation, groups, dnd, sortableJS"/>
+	<meta name="description" content="Sortable — is a JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap."/>
+	<meta name="viewport" content="width=device-width, initial-scale=0.5"/>
+</head>
+<body>
+
+	<a href="https://github.com/SortableJS/Sortable"><img style="position: fixed; top: 0; right: 0; border: 0; z-index:99999" src="https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png" alt="Fork me on GitHub"></a>
+
+	<div class="container">
+		<div class="text-center row header">
+			<img class="mx-auto d-block" src="st/og-image.png" style="max-width: 200px; max-height: 200px" />
+			<h1 class="col-12">SortableJS</h1>
+			<h3 class="col-12 text-center">JavaScript library for reorderable drag-and-drop lists</h3>
+
+			<div class="toc col-12 col-md-5 mt-3">
+				<h5>Features</h5>
+				<li><a href="#simple-list">Simple list</a></li>
+				<li><a href="#shared-lists">Shared lists</a></li>
+				<li><a href="#cloning">Cloning</a></li>
+				<li><a href="#sorting-disabled">Disabling sorting</a></li>
+				<li><a href="#handle">Handles</a></li>
+				<li><a href="#filter">Filter</a></li>
+				<li><a href="#thresholds">Thresholds</a></li>
+				<h5>Examples</h5>
+				<li><a href="#grid">Grid</a></li>
+				<li><a href="#nested">Nested sortables</a></li>
+				<h5>Plugins</h5>
+				<li><a href="#multi-drag">MultiDrag</a></li>
+				<li><a href="#swap">Swap</a></li>
+				<h5><a href="#comparisons">Comparisons</a></h5>
+				<h5><a href="#frameworks">Framework Support</a></h5>
+			</div>
+		</div>
+
+		<div class="row">
+			<h2 class="col-12">Features</h2>
+		</div>
+		<hr />
+		<div id="simple-list" class="row">
+			<h4 class="col-12">Simple list example</h4>
+			<div id="example1" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+				<div class="list-group-item">Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example1, {
+    animation: 150,
+    ghostClass: 'blue-background-class'
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="shared-lists" class="row">
+			<h4 class="col-12">Shared lists</h4>
+			<div id="example2-left" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+				<div class="list-group-item">Item 6</div>
+			</div>
+
+			<div id="example2-right" class="list-group col">
+				<div class="list-group-item tinted">Item 1</div>
+				<div class="list-group-item tinted">Item 2</div>
+				<div class="list-group-item tinted">Item 3</div>
+				<div class="list-group-item tinted">Item 4</div>
+				<div class="list-group-item tinted">Item 5</div>
+				<div class="list-group-item tinted">Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example2Left, {
+    group: 'shared', // set both lists to same group
+    animation: 150
+});
+
+new Sortable(example2Right, {
+    group: 'shared',
+    animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="cloning" class="row">
+			<h4 class="col-12">Cloning</h4>
+			<p class="col-12">Try dragging from one list to another. The item you drag will be cloned and the clone will stay in the original list.</p>
+			<div id="example3-left" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+				<div class="list-group-item">Item 6</div>
+			</div>
+
+			<div id="example3-right" class="list-group col">
+				<div class="list-group-item tinted">Item 1</div>
+				<div class="list-group-item tinted">Item 2</div>
+				<div class="list-group-item tinted">Item 3</div>
+				<div class="list-group-item tinted">Item 4</div>
+				<div class="list-group-item tinted">Item 5</div>
+				<div class="list-group-item tinted">Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example3Left, {
+    group: {
+        name: 'shared',
+        pull: 'clone' // To clone: set pull to 'clone'
+    },
+    animation: 150
+});
+
+new Sortable(example3Right, {
+    group: {
+        name: 'shared',
+        pull: 'clone'
+    },
+    animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="sorting-disabled" class="row">
+			<h4 class="col-12">Disabling Sorting</h4>
+			<p class="col-12">Try sorting the list on the left. It is not possible because it has it's <code>sort</code> option set to false. However, you can still drag from the list on the left to the list on the right.</p>
+			<div id="example4-left" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+				<div class="list-group-item">Item 6</div>
+			</div>
+
+			<div id="example4-right" class="list-group col">
+				<div class="list-group-item tinted">Item 1</div>
+				<div class="list-group-item tinted">Item 2</div>
+				<div class="list-group-item tinted">Item 3</div>
+				<div class="list-group-item tinted">Item 4</div>
+				<div class="list-group-item tinted">Item 5</div>
+				<div class="list-group-item tinted">Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example4Left, {
+    group: {
+        name: 'shared',
+        pull: 'clone',
+        put: false // Do not allow items to be put into this list
+    },
+    animation: 150,
+    sort: false // To disable sorting: set sort to false
+});
+
+new Sortable(example4Right, {
+    group: 'shared',
+    animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="handle" class="row">
+			<h4 class="col-12">Handle</h4>
+			<div id="example5" class="list-group col">
+				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 1</div>
+				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 2</div>
+				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 3</div>
+				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 4</div>
+				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 5</div>
+				<div class="list-group-item"><i class="fas fa-arrows-alt handle"></i>&nbsp;&nbsp;Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example5, {
+    handle: '.handle', // handle's class
+    animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="filter" class="row">
+			<h4 class="col-12">Filter</h4>
+			<p class="col-12">Try dragging the item with a red background. It cannot be done, because that item is filtered out using the <code>filter</code> option.</p>
+			<div id="example6" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item bg-danger filtered">Filtered</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example6, {
+    filter: '.filtered', // 'filtered' class is not draggable
+    animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="thresholds" class="row">
+			<h4 class="col-12">Thresholds</h4>
+			<p class="col-12">Try modifying the inputs below to affect the swap thresholds. You can see the swap zones of the squares colored in dark blue, while the "dead zones" (that do not cause a swap) are colored in light blue.</p>
+			<div id="example7" class="square-section col">
+				<div class="square">
+					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-left"></div>
+					<div class="swap-threshold-indicator"></div>
+					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-right"></div>
+					<div class="num-indicator">1</div>
+				</div><!--
+			 --><div class="square">
+					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-left"></div>
+					<div class="swap-threshold-indicator"></div>
+					<div style="display: none;" class="inverted-swap-threshold-indicator indicator-right"></div>
+					<div class="num-indicator">2</div>
+				</div>
+			</div>
+			<div class="col-12 input-section">
+				<form>
+					<div class="form-group row">
+						<label class="col-sm-2 col-form-label" for="example7SwapThresholdInput">Swap Threshold</label>
+						<div class="col-sm-8 col-form-label">
+							<input min="0" max="1" value="1" step="0.01" type="range" class="form-control-range" id="example7SwapThresholdInput">
+						</div>
+					</div>
+					<div class="form-group row">
+						<div class="col-sm-2">Invert Swap</div>
+						<div class="col-sm-10">
+							<div class="form-check">
+								<input class="form-check-input" type="checkbox" id="example7InvertSwapInput">
+							</div>
+						</div>
+					</div>
+					<div class="form-group row">
+						<label class="col-sm-2 col-form-label" for="example7DirectionInput">Direction</label>
+						<select class="col-sm-4 form-control" id="example7DirectionInput">
+							<option value="h" selected>Horizontal</option>
+							<option value="v">Vertical</option>
+						</select>
+					</div>
+				</form>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(example7, {
+    swapThreshold: <span id="example7SwapThresholdCode">1</span>,<span id="example7InvertSwapCode" style="display: none">
+    invertSwap: true,</span>
+    animation: 150
+});</pre>
+			</div>
+		</div>
+
+
+		<div class="row">
+			<h2 class="col-12">Examples</h2>
+		</div>
+		<hr />
+
+		<div id="grid" class="row">
+			<h4 class="col-12">Grid Example</h4>
+			<div id="gridDemo" class="col">
+				<div class="grid-square">Item 1</div><!--
+			 --><div class="grid-square">Item 2</div><!--
+			 --><div class="grid-square">Item 3</div><!--
+			 --><div class="grid-square">Item 4</div><!--
+			 --><div class="grid-square">Item 5</div><!--
+			 --><div class="grid-square">Item 6</div><!--
+			 --><div class="grid-square">Item 7</div><!--
+			 --><div class="grid-square">Item 8</div><!--
+			 --><div class="grid-square">Item 9</div><!--
+			 --><div class="grid-square">Item 10</div><!--
+			 --><div class="grid-square">Item 11</div><!--
+			 --><div class="grid-square">Item 12</div><!--
+			 --><div class="grid-square">Item 13</div><!--
+			 --><div class="grid-square">Item 14</div><!--
+			 --><div class="grid-square">Item 15</div><!--
+			 --><div class="grid-square">Item 16</div><!--
+			 --><div class="grid-square">Item 17</div><!--
+			 --><div class="grid-square">Item 18</div><!--
+			 --><div class="grid-square">Item 19</div><!--
+			 --><div class="grid-square">Item 20</div>
+			</div>
+		</div>
+		<hr />
+
+		<div id="nested" class="row">
+			<h4 class="col-12">Nested Sortables Example</h4>
+			<p class="col-12">NOTE: When using nested Sortables with animation, it is recommended that the <code>fallbackOnBody</code> option is set to true. <br />It is also always recommended that either the <code>invertSwap</code> option is set to true, or the <code>swapThreshold</code> option is lower than the default value of 1 (eg <code>0.65</code>).</p>
+			<div id="nestedDemo" class="list-group col nested-sortable">
+				<div class="list-group-item nested-1">Item 1.1
+					<div class="list-group nested-sortable">
+						<div class="list-group-item nested-2">Item 2.1</div>
+						<div class="list-group-item nested-2">Item 2.2
+							<div class="list-group nested-sortable">
+								<div class="list-group-item nested-3">Item 3.1</div>
+								<div class="list-group-item nested-3">Item 3.2</div>
+								<div class="list-group-item nested-3">Item 3.3</div>
+								<div class="list-group-item nested-3">Item 3.4</div>
+							</div>
+						</div>
+						<div class="list-group-item nested-2">Item 2.3</div>
+						<div class="list-group-item nested-2">Item 2.4</div>
+					</div>
+				</div>
+				<div class="list-group-item nested-1">Item 1.2</div>
+				<div class="list-group-item nested-1">Item 1.3</div>
+				<div class="list-group-item nested-1">Item 1.4
+					<div class="list-group nested-sortable">
+						<div class="list-group-item nested-2">Item 2.1</div>
+						<div class="list-group-item nested-2">Item 2.2</div>
+						<div class="list-group-item nested-2">Item 2.3</div>
+						<div class="list-group-item nested-2">Item 2.4</div>
+					</div>
+				</div>
+				<div class="list-group-item nested-1">Item 1.5</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">// Loop through each nested sortable element
+for (var i = 0; i < nestedSortables.length; i++) {
+	new Sortable(nestedSortables[i], {
+		group: 'nested',
+		animation: 150,
+		fallbackOnBody: true,
+		swapThreshold: 0.65
+	});
+}</pre>
+			</div>
+		</div>
+
+		<div class="row">
+			<h2 class="col-12">Plugins</h2>
+		</div>
+		<hr />
+
+		<div id="multi-drag" class="row">
+			<h4 class="col-12">MultiDrag</h4>
+			<p class="col-12">The <a target="_blank" href="https://github.com/SortableJS/Sortable/tree/master/plugins/MultiDrag">MultiDrag</a> plugin allows for multiple items to be dragged at a time. You can click to "select" multiple items, and then drag them as one item.</p>
+			<div id="multiDragDemo" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+				<div class="list-group-item">Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(multiDragDemo, {
+	multiDrag: true, // Enable multi-drag
+	selectedClass: 'selected', // The class applied to the selected items
+	animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+		<div id="swap" class="row">
+			<h4 class="col-12">Swap</h4>
+			<p class="col-12">The <a target="_blank" href="https://github.com/SortableJS/Sortable/tree/master/plugins/Swap">Swap</a> plugin changes the behaviour of Sortable to allow for items to be swapped with eachother rather than sorted.</p>
+			<div id="swapDemo" class="list-group col">
+				<div class="list-group-item">Item 1</div>
+				<div class="list-group-item">Item 2</div>
+				<div class="list-group-item">Item 3</div>
+				<div class="list-group-item">Item 4</div>
+				<div class="list-group-item">Item 5</div>
+				<div class="list-group-item">Item 6</div>
+			</div>
+			<div style="padding: 0" class="col-12">
+<pre class="prettyprint">new Sortable(swapDemo, {
+	swap: true, // Enable swap plugin
+	swapClass: 'highlight', // The class applied to the hovered swap item
+	animation: 150
+});</pre>
+			</div>
+		</div>
+		<hr />
+
+
+
+		<div class="mt-4"></div>
+
+		<div id="comparisons" class="row">
+			<h2 class="col-12">Comparisons</h2>
+		</div>
+		<hr />
+
+
+		<div class="row frameworks">
+			<h2 class="col-12 text-center">jQuery-UI</h2>
+			<iframe class="mx-auto" src="https://player.vimeo.com/video/311581236?title=0&byline=0&portrait=0" width="640" height="361" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+
+			<h2 class="col-12 text-center mt-5">Dragula</h2>
+			<iframe class="mx-auto" src="https://player.vimeo.com/video/311584137?title=0&byline=0&portrait=0" width="640" height="361" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
+		</div>
+
+		<div class="mt-4"></div>
+
+		<div id="frameworks" class="row">
+			<h2 class="col-12">Framework Support</h2>
+		</div>
+		<hr />
+
+		<div class="row frameworks">
+
+			<h3 class="col-6">Vue</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/Vue.Draggable">Vue.Draggable</a></h3>
+
+			<h3 class="col-6">React</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/react-sortablejs">react-sortablejs</a></h3>
+
+			<h3 class="col-6">Angular</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/ngx-sortablejs">ngx-sortablejs</a></h3>
+
+			<h3 class="col-6">jQuery</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/jquery-sortablejs">jquery-sortablejs</a></h3>
+
+			<h3 class="col-6">Knockout</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/knockout-sortablejs">knockout-sortablejs</a></h3>
+
+			<h3 class="col-6">Meteor</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/meteor-sortablejs">meteor-sortablejs</a></h3>
+
+			<h3 class="col-6">Polymer</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/polymer-sortablejs">polymer-sortablejs</a></h3>
+
+			<h3 class="col-6">Ember</h3>
+			<h3 class="col-6"><a target="_blank" href="https://github.com/SortableJS/ember-sortablejs">ember-sortablejs</a></h3>
+		</div>
+
+	</div>
+
+
+	<!-- Latest Sortable -->
+	<script src="./Sortable.js"></script>
+
+	<script type="text/javascript" src="st/prettify/prettify.js"></script>
+	<script type="text/javascript" src="st/prettify/run_prettify.js"></script>
+
+	<script src="st/app.js"></script>
+</body>
+</html>

+ 3701 - 0
public/assets/libs/Sortable/modular/sortable.complete.esm.js

@@ -0,0 +1,3701 @@
+/**!
+ * Sortable 1.10.2
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @author	owenm    <owen23355@gmail.com>
+ * @license MIT
+ */
+function _typeof(obj) {
+  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+    _typeof = function (obj) {
+      return typeof obj;
+    };
+  } else {
+    _typeof = function (obj) {
+      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    };
+  }
+
+  return _typeof(obj);
+}
+
+function _defineProperty(obj, key, value) {
+  if (key in obj) {
+    Object.defineProperty(obj, key, {
+      value: value,
+      enumerable: true,
+      configurable: true,
+      writable: true
+    });
+  } else {
+    obj[key] = value;
+  }
+
+  return obj;
+}
+
+function _extends() {
+  _extends = Object.assign || function (target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i];
+
+      for (var key in source) {
+        if (Object.prototype.hasOwnProperty.call(source, key)) {
+          target[key] = source[key];
+        }
+      }
+    }
+
+    return target;
+  };
+
+  return _extends.apply(this, arguments);
+}
+
+function _objectSpread(target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i] != null ? arguments[i] : {};
+    var ownKeys = Object.keys(source);
+
+    if (typeof Object.getOwnPropertySymbols === 'function') {
+      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
+        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
+      }));
+    }
+
+    ownKeys.forEach(function (key) {
+      _defineProperty(target, key, source[key]);
+    });
+  }
+
+  return target;
+}
+
+function _objectWithoutPropertiesLoose(source, excluded) {
+  if (source == null) return {};
+  var target = {};
+  var sourceKeys = Object.keys(source);
+  var key, i;
+
+  for (i = 0; i < sourceKeys.length; i++) {
+    key = sourceKeys[i];
+    if (excluded.indexOf(key) >= 0) continue;
+    target[key] = source[key];
+  }
+
+  return target;
+}
+
+function _objectWithoutProperties(source, excluded) {
+  if (source == null) return {};
+
+  var target = _objectWithoutPropertiesLoose(source, excluded);
+
+  var key, i;
+
+  if (Object.getOwnPropertySymbols) {
+    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
+
+    for (i = 0; i < sourceSymbolKeys.length; i++) {
+      key = sourceSymbolKeys[i];
+      if (excluded.indexOf(key) >= 0) continue;
+      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
+      target[key] = source[key];
+    }
+  }
+
+  return target;
+}
+
+function _toConsumableArray(arr) {
+  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
+}
+
+function _arrayWithoutHoles(arr) {
+  if (Array.isArray(arr)) {
+    for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
+
+    return arr2;
+  }
+}
+
+function _iterableToArray(iter) {
+  if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
+}
+
+function _nonIterableSpread() {
+  throw new TypeError("Invalid attempt to spread non-iterable instance");
+}
+
+var version = "1.10.2";
+
+function userAgent(pattern) {
+  if (typeof window !== 'undefined' && window.navigator) {
+    return !!
+    /*@__PURE__*/
+    navigator.userAgent.match(pattern);
+  }
+}
+
+var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
+var Edge = userAgent(/Edge/i);
+var FireFox = userAgent(/firefox/i);
+var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
+var IOS = userAgent(/iP(ad|od|hone)/i);
+var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
+
+var captureMode = {
+  capture: false,
+  passive: false
+};
+
+function on(el, event, fn) {
+  el.addEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function off(el, event, fn) {
+  el.removeEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function matches(
+/**HTMLElement*/
+el,
+/**String*/
+selector) {
+  if (!selector) return;
+  selector[0] === '>' && (selector = selector.substring(1));
+
+  if (el) {
+    try {
+      if (el.matches) {
+        return el.matches(selector);
+      } else if (el.msMatchesSelector) {
+        return el.msMatchesSelector(selector);
+      } else if (el.webkitMatchesSelector) {
+        return el.webkitMatchesSelector(selector);
+      }
+    } catch (_) {
+      return false;
+    }
+  }
+
+  return false;
+}
+
+function getParentOrHost(el) {
+  return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
+}
+
+function closest(
+/**HTMLElement*/
+el,
+/**String*/
+selector,
+/**HTMLElement*/
+ctx, includeCTX) {
+  if (el) {
+    ctx = ctx || document;
+
+    do {
+      if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
+        return el;
+      }
+
+      if (el === ctx) break;
+      /* jshint boss:true */
+    } while (el = getParentOrHost(el));
+  }
+
+  return null;
+}
+
+var R_SPACE = /\s+/g;
+
+function toggleClass(el, name, state) {
+  if (el && name) {
+    if (el.classList) {
+      el.classList[state ? 'add' : 'remove'](name);
+    } else {
+      var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
+      el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
+    }
+  }
+}
+
+function css(el, prop, val) {
+  var style = el && el.style;
+
+  if (style) {
+    if (val === void 0) {
+      if (document.defaultView && document.defaultView.getComputedStyle) {
+        val = document.defaultView.getComputedStyle(el, '');
+      } else if (el.currentStyle) {
+        val = el.currentStyle;
+      }
+
+      return prop === void 0 ? val : val[prop];
+    } else {
+      if (!(prop in style) && prop.indexOf('webkit') === -1) {
+        prop = '-webkit-' + prop;
+      }
+
+      style[prop] = val + (typeof val === 'string' ? '' : 'px');
+    }
+  }
+}
+
+function matrix(el, selfOnly) {
+  var appliedTransforms = '';
+
+  if (typeof el === 'string') {
+    appliedTransforms = el;
+  } else {
+    do {
+      var transform = css(el, 'transform');
+
+      if (transform && transform !== 'none') {
+        appliedTransforms = transform + ' ' + appliedTransforms;
+      }
+      /* jshint boss:true */
+
+    } while (!selfOnly && (el = el.parentNode));
+  }
+
+  var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
+  /*jshint -W056 */
+
+  return matrixFn && new matrixFn(appliedTransforms);
+}
+
+function find(ctx, tagName, iterator) {
+  if (ctx) {
+    var list = ctx.getElementsByTagName(tagName),
+        i = 0,
+        n = list.length;
+
+    if (iterator) {
+      for (; i < n; i++) {
+        iterator(list[i], i);
+      }
+    }
+
+    return list;
+  }
+
+  return [];
+}
+
+function getWindowScrollingElement() {
+  var scrollingElement = document.scrollingElement;
+
+  if (scrollingElement) {
+    return scrollingElement;
+  } else {
+    return document.documentElement;
+  }
+}
+/**
+ * Returns the "bounding client rect" of given element
+ * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
+ * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
+ * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
+ * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
+ * @param  {[HTMLElement]} container              The parent the element will be placed in
+ * @return {Object}                               The boundingClientRect of el, with specified adjustments
+ */
+
+
+function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
+  if (!el.getBoundingClientRect && el !== window) return;
+  var elRect, top, left, bottom, right, height, width;
+
+  if (el !== window && el !== getWindowScrollingElement()) {
+    elRect = el.getBoundingClientRect();
+    top = elRect.top;
+    left = elRect.left;
+    bottom = elRect.bottom;
+    right = elRect.right;
+    height = elRect.height;
+    width = elRect.width;
+  } else {
+    top = 0;
+    left = 0;
+    bottom = window.innerHeight;
+    right = window.innerWidth;
+    height = window.innerHeight;
+    width = window.innerWidth;
+  }
+
+  if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
+    // Adjust for translate()
+    container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
+    // Not needed on <= IE11
+
+    if (!IE11OrLess) {
+      do {
+        if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
+          var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
+
+          top -= containerRect.top + parseInt(css(container, 'border-top-width'));
+          left -= containerRect.left + parseInt(css(container, 'border-left-width'));
+          bottom = top + elRect.height;
+          right = left + elRect.width;
+          break;
+        }
+        /* jshint boss:true */
+
+      } while (container = container.parentNode);
+    }
+  }
+
+  if (undoScale && el !== window) {
+    // Adjust for scale()
+    var elMatrix = matrix(container || el),
+        scaleX = elMatrix && elMatrix.a,
+        scaleY = elMatrix && elMatrix.d;
+
+    if (elMatrix) {
+      top /= scaleY;
+      left /= scaleX;
+      width /= scaleX;
+      height /= scaleY;
+      bottom = top + height;
+      right = left + width;
+    }
+  }
+
+  return {
+    top: top,
+    left: left,
+    bottom: bottom,
+    right: right,
+    width: width,
+    height: height
+  };
+}
+/**
+ * Checks if a side of an element is scrolled past a side of its parents
+ * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
+ * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
+ * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
+ * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
+ */
+
+
+function isScrolledPast(el, elSide, parentSide) {
+  var parent = getParentAutoScrollElement(el, true),
+      elSideVal = getRect(el)[elSide];
+  /* jshint boss:true */
+
+  while (parent) {
+    var parentSideVal = getRect(parent)[parentSide],
+        visible = void 0;
+
+    if (parentSide === 'top' || parentSide === 'left') {
+      visible = elSideVal >= parentSideVal;
+    } else {
+      visible = elSideVal <= parentSideVal;
+    }
+
+    if (!visible) return parent;
+    if (parent === getWindowScrollingElement()) break;
+    parent = getParentAutoScrollElement(parent, false);
+  }
+
+  return false;
+}
+/**
+ * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
+ * and non-draggable elements
+ * @param  {HTMLElement} el       The parent element
+ * @param  {Number} childNum      The index of the child
+ * @param  {Object} options       Parent Sortable's options
+ * @return {HTMLElement}          The child at index childNum, or null if not found
+ */
+
+
+function getChild(el, childNum, options) {
+  var currentChild = 0,
+      i = 0,
+      children = el.children;
+
+  while (i < children.length) {
+    if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && children[i] !== Sortable.dragged && closest(children[i], options.draggable, el, false)) {
+      if (currentChild === childNum) {
+        return children[i];
+      }
+
+      currentChild++;
+    }
+
+    i++;
+  }
+
+  return null;
+}
+/**
+ * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
+ * @param  {HTMLElement} el       Parent element
+ * @param  {selector} selector    Any other elements that should be ignored
+ * @return {HTMLElement}          The last child, ignoring ghostEl
+ */
+
+
+function lastChild(el, selector) {
+  var last = el.lastElementChild;
+
+  while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
+    last = last.previousElementSibling;
+  }
+
+  return last || null;
+}
+/**
+ * Returns the index of an element within its parent for a selected set of
+ * elements
+ * @param  {HTMLElement} el
+ * @param  {selector} selector
+ * @return {number}
+ */
+
+
+function index(el, selector) {
+  var index = 0;
+
+  if (!el || !el.parentNode) {
+    return -1;
+  }
+  /* jshint boss:true */
+
+
+  while (el = el.previousElementSibling) {
+    if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
+      index++;
+    }
+  }
+
+  return index;
+}
+/**
+ * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
+ * The value is returned in real pixels.
+ * @param  {HTMLElement} el
+ * @return {Array}             Offsets in the format of [left, top]
+ */
+
+
+function getRelativeScrollOffset(el) {
+  var offsetLeft = 0,
+      offsetTop = 0,
+      winScroller = getWindowScrollingElement();
+
+  if (el) {
+    do {
+      var elMatrix = matrix(el),
+          scaleX = elMatrix.a,
+          scaleY = elMatrix.d;
+      offsetLeft += el.scrollLeft * scaleX;
+      offsetTop += el.scrollTop * scaleY;
+    } while (el !== winScroller && (el = el.parentNode));
+  }
+
+  return [offsetLeft, offsetTop];
+}
+/**
+ * Returns the index of the object within the given array
+ * @param  {Array} arr   Array that may or may not hold the object
+ * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
+ * @return {Number}      The index of the object in the array, or -1
+ */
+
+
+function indexOfObject(arr, obj) {
+  for (var i in arr) {
+    if (!arr.hasOwnProperty(i)) continue;
+
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
+    }
+  }
+
+  return -1;
+}
+
+function getParentAutoScrollElement(el, includeSelf) {
+  // skip to window
+  if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
+  var elem = el;
+  var gotSelf = false;
+
+  do {
+    // we don't need to get elem css if it isn't even overflowing in the first place (performance)
+    if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
+      var elemCSS = css(elem);
+
+      if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
+        if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
+        if (gotSelf || includeSelf) return elem;
+        gotSelf = true;
+      }
+    }
+    /* jshint boss:true */
+
+  } while (elem = elem.parentNode);
+
+  return getWindowScrollingElement();
+}
+
+function extend(dst, src) {
+  if (dst && src) {
+    for (var key in src) {
+      if (src.hasOwnProperty(key)) {
+        dst[key] = src[key];
+      }
+    }
+  }
+
+  return dst;
+}
+
+function isRectEqual(rect1, rect2) {
+  return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
+}
+
+var _throttleTimeout;
+
+function throttle(callback, ms) {
+  return function () {
+    if (!_throttleTimeout) {
+      var args = arguments,
+          _this = this;
+
+      if (args.length === 1) {
+        callback.call(_this, args[0]);
+      } else {
+        callback.apply(_this, args);
+      }
+
+      _throttleTimeout = setTimeout(function () {
+        _throttleTimeout = void 0;
+      }, ms);
+    }
+  };
+}
+
+function cancelThrottle() {
+  clearTimeout(_throttleTimeout);
+  _throttleTimeout = void 0;
+}
+
+function scrollBy(el, x, y) {
+  el.scrollLeft += x;
+  el.scrollTop += y;
+}
+
+function clone(el) {
+  var Polymer = window.Polymer;
+  var $ = window.jQuery || window.Zepto;
+
+  if (Polymer && Polymer.dom) {
+    return Polymer.dom(el).cloneNode(true);
+  } else if ($) {
+    return $(el).clone(true)[0];
+  } else {
+    return el.cloneNode(true);
+  }
+}
+
+function setRect(el, rect) {
+  css(el, 'position', 'absolute');
+  css(el, 'top', rect.top);
+  css(el, 'left', rect.left);
+  css(el, 'width', rect.width);
+  css(el, 'height', rect.height);
+}
+
+function unsetRect(el) {
+  css(el, 'position', '');
+  css(el, 'top', '');
+  css(el, 'left', '');
+  css(el, 'width', '');
+  css(el, 'height', '');
+}
+
+var expando = 'Sortable' + new Date().getTime();
+
+function AnimationStateManager() {
+  var animationStates = [],
+      animationCallbackId;
+  return {
+    captureAnimationState: function captureAnimationState() {
+      animationStates = [];
+      if (!this.options.animation) return;
+      var children = [].slice.call(this.el.children);
+      children.forEach(function (child) {
+        if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
+        animationStates.push({
+          target: child,
+          rect: getRect(child)
+        });
+
+        var fromRect = _objectSpread({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation
+
+
+        if (child.thisAnimationDuration) {
+          var childMatrix = matrix(child, true);
+
+          if (childMatrix) {
+            fromRect.top -= childMatrix.f;
+            fromRect.left -= childMatrix.e;
+          }
+        }
+
+        child.fromRect = fromRect;
+      });
+    },
+    addAnimationState: function addAnimationState(state) {
+      animationStates.push(state);
+    },
+    removeAnimationState: function removeAnimationState(target) {
+      animationStates.splice(indexOfObject(animationStates, {
+        target: target
+      }), 1);
+    },
+    animateAll: function animateAll(callback) {
+      var _this = this;
+
+      if (!this.options.animation) {
+        clearTimeout(animationCallbackId);
+        if (typeof callback === 'function') callback();
+        return;
+      }
+
+      var animating = false,
+          animationTime = 0;
+      animationStates.forEach(function (state) {
+        var time = 0,
+            target = state.target,
+            fromRect = target.fromRect,
+            toRect = getRect(target),
+            prevFromRect = target.prevFromRect,
+            prevToRect = target.prevToRect,
+            animatingRect = state.rect,
+            targetMatrix = matrix(target, true);
+
+        if (targetMatrix) {
+          // Compensate for current animation
+          toRect.top -= targetMatrix.f;
+          toRect.left -= targetMatrix.e;
+        }
+
+        target.toRect = toRect;
+
+        if (target.thisAnimationDuration) {
+          // Could also check if animatingRect is between fromRect and toRect
+          if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
+          (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
+            // If returning to same place as started from animation and on same axis
+            time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
+          }
+        } // if fromRect != toRect: animate
+
+
+        if (!isRectEqual(toRect, fromRect)) {
+          target.prevFromRect = fromRect;
+          target.prevToRect = toRect;
+
+          if (!time) {
+            time = _this.options.animation;
+          }
+
+          _this.animate(target, animatingRect, toRect, time);
+        }
+
+        if (time) {
+          animating = true;
+          animationTime = Math.max(animationTime, time);
+          clearTimeout(target.animationResetTimer);
+          target.animationResetTimer = setTimeout(function () {
+            target.animationTime = 0;
+            target.prevFromRect = null;
+            target.fromRect = null;
+            target.prevToRect = null;
+            target.thisAnimationDuration = null;
+          }, time);
+          target.thisAnimationDuration = time;
+        }
+      });
+      clearTimeout(animationCallbackId);
+
+      if (!animating) {
+        if (typeof callback === 'function') callback();
+      } else {
+        animationCallbackId = setTimeout(function () {
+          if (typeof callback === 'function') callback();
+        }, animationTime);
+      }
+
+      animationStates = [];
+    },
+    animate: function animate(target, currentRect, toRect, duration) {
+      if (duration) {
+        css(target, 'transition', '');
+        css(target, 'transform', '');
+        var elMatrix = matrix(this.el),
+            scaleX = elMatrix && elMatrix.a,
+            scaleY = elMatrix && elMatrix.d,
+            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
+            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
+        target.animatingX = !!translateX;
+        target.animatingY = !!translateY;
+        css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
+        repaint(target); // repaint
+
+        css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
+        css(target, 'transform', 'translate3d(0,0,0)');
+        typeof target.animated === 'number' && clearTimeout(target.animated);
+        target.animated = setTimeout(function () {
+          css(target, 'transition', '');
+          css(target, 'transform', '');
+          target.animated = false;
+          target.animatingX = false;
+          target.animatingY = false;
+        }, duration);
+      }
+    }
+  };
+}
+
+function repaint(target) {
+  return target.offsetWidth;
+}
+
+function calculateRealTime(animatingRect, fromRect, toRect, options) {
+  return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
+}
+
+var plugins = [];
+var defaults = {
+  initializeByDefault: true
+};
+var PluginManager = {
+  mount: function mount(plugin) {
+    // Set default static properties
+    for (var option in defaults) {
+      if (defaults.hasOwnProperty(option) && !(option in plugin)) {
+        plugin[option] = defaults[option];
+      }
+    }
+
+    plugins.push(plugin);
+  },
+  pluginEvent: function pluginEvent(eventName, sortable, evt) {
+    var _this = this;
+
+    this.eventCanceled = false;
+
+    evt.cancel = function () {
+      _this.eventCanceled = true;
+    };
+
+    var eventNameGlobal = eventName + 'Global';
+    plugins.forEach(function (plugin) {
+      if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
+
+      if (sortable[plugin.pluginName][eventNameGlobal]) {
+        sortable[plugin.pluginName][eventNameGlobal](_objectSpread({
+          sortable: sortable
+        }, evt));
+      } // Only fire plugin event if plugin is enabled in this sortable,
+      // and plugin has event defined
+
+
+      if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
+        sortable[plugin.pluginName][eventName](_objectSpread({
+          sortable: sortable
+        }, evt));
+      }
+    });
+  },
+  initializePlugins: function initializePlugins(sortable, el, defaults, options) {
+    plugins.forEach(function (plugin) {
+      var pluginName = plugin.pluginName;
+      if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
+      var initialized = new plugin(sortable, el, sortable.options);
+      initialized.sortable = sortable;
+      initialized.options = sortable.options;
+      sortable[pluginName] = initialized; // Add default options from plugin
+
+      _extends(defaults, initialized.defaults);
+    });
+
+    for (var option in sortable.options) {
+      if (!sortable.options.hasOwnProperty(option)) continue;
+      var modified = this.modifyOption(sortable, option, sortable.options[option]);
+
+      if (typeof modified !== 'undefined') {
+        sortable.options[option] = modified;
+      }
+    }
+  },
+  getEventProperties: function getEventProperties(name, sortable) {
+    var eventProperties = {};
+    plugins.forEach(function (plugin) {
+      if (typeof plugin.eventProperties !== 'function') return;
+
+      _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
+    });
+    return eventProperties;
+  },
+  modifyOption: function modifyOption(sortable, name, value) {
+    var modifiedValue;
+    plugins.forEach(function (plugin) {
+      // Plugin must exist on the Sortable
+      if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
+
+      if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
+        modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
+      }
+    });
+    return modifiedValue;
+  }
+};
+
+function dispatchEvent(_ref) {
+  var sortable = _ref.sortable,
+      rootEl = _ref.rootEl,
+      name = _ref.name,
+      targetEl = _ref.targetEl,
+      cloneEl = _ref.cloneEl,
+      toEl = _ref.toEl,
+      fromEl = _ref.fromEl,
+      oldIndex = _ref.oldIndex,
+      newIndex = _ref.newIndex,
+      oldDraggableIndex = _ref.oldDraggableIndex,
+      newDraggableIndex = _ref.newDraggableIndex,
+      originalEvent = _ref.originalEvent,
+      putSortable = _ref.putSortable,
+      extraEventProperties = _ref.extraEventProperties;
+  sortable = sortable || rootEl && rootEl[expando];
+  if (!sortable) return;
+  var evt,
+      options = sortable.options,
+      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
+
+  if (window.CustomEvent && !IE11OrLess && !Edge) {
+    evt = new CustomEvent(name, {
+      bubbles: true,
+      cancelable: true
+    });
+  } else {
+    evt = document.createEvent('Event');
+    evt.initEvent(name, true, true);
+  }
+
+  evt.to = toEl || rootEl;
+  evt.from = fromEl || rootEl;
+  evt.item = targetEl || rootEl;
+  evt.clone = cloneEl;
+  evt.oldIndex = oldIndex;
+  evt.newIndex = newIndex;
+  evt.oldDraggableIndex = oldDraggableIndex;
+  evt.newDraggableIndex = newDraggableIndex;
+  evt.originalEvent = originalEvent;
+  evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
+
+  var allEventProperties = _objectSpread({}, extraEventProperties, PluginManager.getEventProperties(name, sortable));
+
+  for (var option in allEventProperties) {
+    evt[option] = allEventProperties[option];
+  }
+
+  if (rootEl) {
+    rootEl.dispatchEvent(evt);
+  }
+
+  if (options[onName]) {
+    options[onName].call(sortable, evt);
+  }
+}
+
+var pluginEvent = function pluginEvent(eventName, sortable) {
+  var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
+      originalEvent = _ref.evt,
+      data = _objectWithoutProperties(_ref, ["evt"]);
+
+  PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread({
+    dragEl: dragEl,
+    parentEl: parentEl,
+    ghostEl: ghostEl,
+    rootEl: rootEl,
+    nextEl: nextEl,
+    lastDownEl: lastDownEl,
+    cloneEl: cloneEl,
+    cloneHidden: cloneHidden,
+    dragStarted: moved,
+    putSortable: putSortable,
+    activeSortable: Sortable.active,
+    originalEvent: originalEvent,
+    oldIndex: oldIndex,
+    oldDraggableIndex: oldDraggableIndex,
+    newIndex: newIndex,
+    newDraggableIndex: newDraggableIndex,
+    hideGhostForTarget: _hideGhostForTarget,
+    unhideGhostForTarget: _unhideGhostForTarget,
+    cloneNowHidden: function cloneNowHidden() {
+      cloneHidden = true;
+    },
+    cloneNowShown: function cloneNowShown() {
+      cloneHidden = false;
+    },
+    dispatchSortableEvent: function dispatchSortableEvent(name) {
+      _dispatchEvent({
+        sortable: sortable,
+        name: name,
+        originalEvent: originalEvent
+      });
+    }
+  }, data));
+};
+
+function _dispatchEvent(info) {
+  dispatchEvent(_objectSpread({
+    putSortable: putSortable,
+    cloneEl: cloneEl,
+    targetEl: dragEl,
+    rootEl: rootEl,
+    oldIndex: oldIndex,
+    oldDraggableIndex: oldDraggableIndex,
+    newIndex: newIndex,
+    newDraggableIndex: newDraggableIndex
+  }, info));
+}
+
+var dragEl,
+    parentEl,
+    ghostEl,
+    rootEl,
+    nextEl,
+    lastDownEl,
+    cloneEl,
+    cloneHidden,
+    oldIndex,
+    newIndex,
+    oldDraggableIndex,
+    newDraggableIndex,
+    activeGroup,
+    putSortable,
+    awaitingDragStarted = false,
+    ignoreNextClick = false,
+    sortables = [],
+    tapEvt,
+    touchEvt,
+    lastDx,
+    lastDy,
+    tapDistanceLeft,
+    tapDistanceTop,
+    moved,
+    lastTarget,
+    lastDirection,
+    pastFirstInvertThresh = false,
+    isCircumstantialInvert = false,
+    targetMoveDistance,
+    // For positioning ghost absolutely
+ghostRelativeParent,
+    ghostRelativeParentInitialScroll = [],
+    // (left, top)
+_silent = false,
+    savedInputChecked = [];
+/** @const */
+
+var documentExists = typeof document !== 'undefined',
+    PositionGhostAbsolutely = IOS,
+    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
+    // This will not pass for IE9, because IE9 DnD only works on anchors
+supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
+    supportCssPointerEvents = function () {
+  if (!documentExists) return; // false when <= IE11
+
+  if (IE11OrLess) {
+    return false;
+  }
+
+  var el = document.createElement('x');
+  el.style.cssText = 'pointer-events:auto';
+  return el.style.pointerEvents === 'auto';
+}(),
+    _detectDirection = function _detectDirection(el, options) {
+  var elCSS = css(el),
+      elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
+      child1 = getChild(el, 0, options),
+      child2 = getChild(el, 1, options),
+      firstChildCSS = child1 && css(child1),
+      secondChildCSS = child2 && css(child2),
+      firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
+      secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
+
+  if (elCSS.display === 'flex') {
+    return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
+  }
+
+  if (elCSS.display === 'grid') {
+    return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
+  }
+
+  if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
+    var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
+    return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
+  }
+
+  return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
+},
+    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
+  var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
+      dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
+      dragElOppLength = vertical ? dragRect.width : dragRect.height,
+      targetS1Opp = vertical ? targetRect.left : targetRect.top,
+      targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
+      targetOppLength = vertical ? targetRect.width : targetRect.height;
+  return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
+},
+
+/**
+ * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
+ * @param  {Number} x      X position
+ * @param  {Number} y      Y position
+ * @return {HTMLElement}   Element of the first found nearest Sortable
+ */
+_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
+  var ret;
+  sortables.some(function (sortable) {
+    if (lastChild(sortable)) return;
+    var rect = getRect(sortable),
+        threshold = sortable[expando].options.emptyInsertThreshold,
+        insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
+        insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
+
+    if (threshold && insideHorizontally && insideVertically) {
+      return ret = sortable;
+    }
+  });
+  return ret;
+},
+    _prepareGroup = function _prepareGroup(options) {
+  function toFn(value, pull) {
+    return function (to, from, dragEl, evt) {
+      var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
+
+      if (value == null && (pull || sameGroup)) {
+        // Default pull value
+        // Default pull and put value if same group
+        return true;
+      } else if (value == null || value === false) {
+        return false;
+      } else if (pull && value === 'clone') {
+        return value;
+      } else if (typeof value === 'function') {
+        return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
+      } else {
+        var otherGroup = (pull ? to : from).options.group.name;
+        return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
+      }
+    };
+  }
+
+  var group = {};
+  var originalGroup = options.group;
+
+  if (!originalGroup || _typeof(originalGroup) != 'object') {
+    originalGroup = {
+      name: originalGroup
+    };
+  }
+
+  group.name = originalGroup.name;
+  group.checkPull = toFn(originalGroup.pull, true);
+  group.checkPut = toFn(originalGroup.put);
+  group.revertClone = originalGroup.revertClone;
+  options.group = group;
+},
+    _hideGhostForTarget = function _hideGhostForTarget() {
+  if (!supportCssPointerEvents && ghostEl) {
+    css(ghostEl, 'display', 'none');
+  }
+},
+    _unhideGhostForTarget = function _unhideGhostForTarget() {
+  if (!supportCssPointerEvents && ghostEl) {
+    css(ghostEl, 'display', '');
+  }
+}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
+
+
+if (documentExists) {
+  document.addEventListener('click', function (evt) {
+    if (ignoreNextClick) {
+      evt.preventDefault();
+      evt.stopPropagation && evt.stopPropagation();
+      evt.stopImmediatePropagation && evt.stopImmediatePropagation();
+      ignoreNextClick = false;
+      return false;
+    }
+  }, true);
+}
+
+var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
+  if (dragEl) {
+    evt = evt.touches ? evt.touches[0] : evt;
+
+    var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
+
+    if (nearest) {
+      // Create imitation event
+      var event = {};
+
+      for (var i in evt) {
+        if (evt.hasOwnProperty(i)) {
+          event[i] = evt[i];
+        }
+      }
+
+      event.target = event.rootEl = nearest;
+      event.preventDefault = void 0;
+      event.stopPropagation = void 0;
+
+      nearest[expando]._onDragOver(event);
+    }
+  }
+};
+
+var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
+  if (dragEl) {
+    dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
+  }
+};
+/**
+ * @class  Sortable
+ * @param  {HTMLElement}  el
+ * @param  {Object}       [options]
+ */
+
+
+function Sortable(el, options) {
+  if (!(el && el.nodeType && el.nodeType === 1)) {
+    throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
+  }
+
+  this.el = el; // root element
+
+  this.options = options = _extends({}, options); // Export instance
+
+  el[expando] = this;
+  var defaults = {
+    group: null,
+    sort: true,
+    disabled: false,
+    store: null,
+    handle: null,
+    draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
+    swapThreshold: 1,
+    // percentage; 0 <= x <= 1
+    invertSwap: false,
+    // invert always
+    invertedSwapThreshold: null,
+    // will be set to same as swapThreshold if default
+    removeCloneOnHide: true,
+    direction: function direction() {
+      return _detectDirection(el, this.options);
+    },
+    ghostClass: 'sortable-ghost',
+    chosenClass: 'sortable-chosen',
+    dragClass: 'sortable-drag',
+    ignore: 'a, img',
+    filter: null,
+    preventOnFilter: true,
+    animation: 0,
+    easing: null,
+    setData: function setData(dataTransfer, dragEl) {
+      dataTransfer.setData('Text', dragEl.textContent);
+    },
+    dropBubble: false,
+    dragoverBubble: false,
+    dataIdAttr: 'data-id',
+    delay: 0,
+    delayOnTouchOnly: false,
+    touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
+    forceFallback: false,
+    fallbackClass: 'sortable-fallback',
+    fallbackOnBody: false,
+    fallbackTolerance: 0,
+    fallbackOffset: {
+      x: 0,
+      y: 0
+    },
+    supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window,
+    emptyInsertThreshold: 5
+  };
+  PluginManager.initializePlugins(this, el, defaults); // Set default options
+
+  for (var name in defaults) {
+    !(name in options) && (options[name] = defaults[name]);
+  }
+
+  _prepareGroup(options); // Bind all private methods
+
+
+  for (var fn in this) {
+    if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+      this[fn] = this[fn].bind(this);
+    }
+  } // Setup drag mode
+
+
+  this.nativeDraggable = options.forceFallback ? false : supportDraggable;
+
+  if (this.nativeDraggable) {
+    // Touch start threshold cannot be greater than the native dragstart threshold
+    this.options.touchStartThreshold = 1;
+  } // Bind events
+
+
+  if (options.supportPointer) {
+    on(el, 'pointerdown', this._onTapStart);
+  } else {
+    on(el, 'mousedown', this._onTapStart);
+    on(el, 'touchstart', this._onTapStart);
+  }
+
+  if (this.nativeDraggable) {
+    on(el, 'dragover', this);
+    on(el, 'dragenter', this);
+  }
+
+  sortables.push(this.el); // Restore sorting
+
+  options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
+
+  _extends(this, AnimationStateManager());
+}
+
+Sortable.prototype =
+/** @lends Sortable.prototype */
+{
+  constructor: Sortable,
+  _isOutsideThisEl: function _isOutsideThisEl(target) {
+    if (!this.el.contains(target) && target !== this.el) {
+      lastTarget = null;
+    }
+  },
+  _getDirection: function _getDirection(evt, target) {
+    return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
+  },
+  _onTapStart: function _onTapStart(
+  /** Event|TouchEvent */
+  evt) {
+    if (!evt.cancelable) return;
+
+    var _this = this,
+        el = this.el,
+        options = this.options,
+        preventOnFilter = options.preventOnFilter,
+        type = evt.type,
+        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
+        target = (touch || evt).target,
+        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
+        filter = options.filter;
+
+    _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
+
+
+    if (dragEl) {
+      return;
+    }
+
+    if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
+      return; // only left button and enabled
+    } // cancel dnd if original target is content editable
+
+
+    if (originalTarget.isContentEditable) {
+      return;
+    }
+
+    target = closest(target, options.draggable, el, false);
+
+    if (target && target.animated) {
+      return;
+    }
+
+    if (lastDownEl === target) {
+      // Ignoring duplicate `down`
+      return;
+    } // Get the index of the dragged element within its parent
+
+
+    oldIndex = index(target);
+    oldDraggableIndex = index(target, options.draggable); // Check filter
+
+    if (typeof filter === 'function') {
+      if (filter.call(this, evt, target, this)) {
+        _dispatchEvent({
+          sortable: _this,
+          rootEl: originalTarget,
+          name: 'filter',
+          targetEl: target,
+          toEl: el,
+          fromEl: el
+        });
+
+        pluginEvent('filter', _this, {
+          evt: evt
+        });
+        preventOnFilter && evt.cancelable && evt.preventDefault();
+        return; // cancel dnd
+      }
+    } else if (filter) {
+      filter = filter.split(',').some(function (criteria) {
+        criteria = closest(originalTarget, criteria.trim(), el, false);
+
+        if (criteria) {
+          _dispatchEvent({
+            sortable: _this,
+            rootEl: criteria,
+            name: 'filter',
+            targetEl: target,
+            fromEl: el,
+            toEl: el
+          });
+
+          pluginEvent('filter', _this, {
+            evt: evt
+          });
+          return true;
+        }
+      });
+
+      if (filter) {
+        preventOnFilter && evt.cancelable && evt.preventDefault();
+        return; // cancel dnd
+      }
+    }
+
+    if (options.handle && !closest(originalTarget, options.handle, el, false)) {
+      return;
+    } // Prepare `dragstart`
+
+
+    this._prepareDragStart(evt, touch, target);
+  },
+  _prepareDragStart: function _prepareDragStart(
+  /** Event */
+  evt,
+  /** Touch */
+  touch,
+  /** HTMLElement */
+  target) {
+    var _this = this,
+        el = _this.el,
+        options = _this.options,
+        ownerDocument = el.ownerDocument,
+        dragStartFn;
+
+    if (target && !dragEl && target.parentNode === el) {
+      var dragRect = getRect(target);
+      rootEl = el;
+      dragEl = target;
+      parentEl = dragEl.parentNode;
+      nextEl = dragEl.nextSibling;
+      lastDownEl = target;
+      activeGroup = options.group;
+      Sortable.dragged = dragEl;
+      tapEvt = {
+        target: dragEl,
+        clientX: (touch || evt).clientX,
+        clientY: (touch || evt).clientY
+      };
+      tapDistanceLeft = tapEvt.clientX - dragRect.left;
+      tapDistanceTop = tapEvt.clientY - dragRect.top;
+      this._lastX = (touch || evt).clientX;
+      this._lastY = (touch || evt).clientY;
+      dragEl.style['will-change'] = 'all';
+
+      dragStartFn = function dragStartFn() {
+        pluginEvent('delayEnded', _this, {
+          evt: evt
+        });
+
+        if (Sortable.eventCanceled) {
+          _this._onDrop();
+
+          return;
+        } // Delayed drag has been triggered
+        // we can re-enable the events: touchmove/mousemove
+
+
+        _this._disableDelayedDragEvents();
+
+        if (!FireFox && _this.nativeDraggable) {
+          dragEl.draggable = true;
+        } // Bind the events: dragstart/dragend
+
+
+        _this._triggerDragStart(evt, touch); // Drag start event
+
+
+        _dispatchEvent({
+          sortable: _this,
+          name: 'choose',
+          originalEvent: evt
+        }); // Chosen item
+
+
+        toggleClass(dragEl, options.chosenClass, true);
+      }; // Disable "draggable"
+
+
+      options.ignore.split(',').forEach(function (criteria) {
+        find(dragEl, criteria.trim(), _disableDraggable);
+      });
+      on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'mouseup', _this._onDrop);
+      on(ownerDocument, 'touchend', _this._onDrop);
+      on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
+
+      if (FireFox && this.nativeDraggable) {
+        this.options.touchStartThreshold = 4;
+        dragEl.draggable = true;
+      }
+
+      pluginEvent('delayStart', this, {
+        evt: evt
+      }); // Delay is impossible for native DnD in Edge or IE
+
+      if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
+        if (Sortable.eventCanceled) {
+          this._onDrop();
+
+          return;
+        } // If the user moves the pointer or let go the click or touch
+        // before the delay has been reached:
+        // disable the delayed drag
+
+
+        on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
+        on(ownerDocument, 'touchend', _this._disableDelayedDrag);
+        on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
+        on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
+        on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
+        options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
+        _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
+      } else {
+        dragStartFn();
+      }
+    }
+  },
+  _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
+  /** TouchEvent|PointerEvent **/
+  e) {
+    var touch = e.touches ? e.touches[0] : e;
+
+    if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
+      this._disableDelayedDrag();
+    }
+  },
+  _disableDelayedDrag: function _disableDelayedDrag() {
+    dragEl && _disableDraggable(dragEl);
+    clearTimeout(this._dragStartTimer);
+
+    this._disableDelayedDragEvents();
+  },
+  _disableDelayedDragEvents: function _disableDelayedDragEvents() {
+    var ownerDocument = this.el.ownerDocument;
+    off(ownerDocument, 'mouseup', this._disableDelayedDrag);
+    off(ownerDocument, 'touchend', this._disableDelayedDrag);
+    off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
+    off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
+    off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
+    off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
+  },
+  _triggerDragStart: function _triggerDragStart(
+  /** Event */
+  evt,
+  /** Touch */
+  touch) {
+    touch = touch || evt.pointerType == 'touch' && evt;
+
+    if (!this.nativeDraggable || touch) {
+      if (this.options.supportPointer) {
+        on(document, 'pointermove', this._onTouchMove);
+      } else if (touch) {
+        on(document, 'touchmove', this._onTouchMove);
+      } else {
+        on(document, 'mousemove', this._onTouchMove);
+      }
+    } else {
+      on(dragEl, 'dragend', this);
+      on(rootEl, 'dragstart', this._onDragStart);
+    }
+
+    try {
+      if (document.selection) {
+        // Timeout neccessary for IE9
+        _nextTick(function () {
+          document.selection.empty();
+        });
+      } else {
+        window.getSelection().removeAllRanges();
+      }
+    } catch (err) {}
+  },
+  _dragStarted: function _dragStarted(fallback, evt) {
+
+    awaitingDragStarted = false;
+
+    if (rootEl && dragEl) {
+      pluginEvent('dragStarted', this, {
+        evt: evt
+      });
+
+      if (this.nativeDraggable) {
+        on(document, 'dragover', _checkOutsideTargetEl);
+      }
+
+      var options = this.options; // Apply effect
+
+      !fallback && toggleClass(dragEl, options.dragClass, false);
+      toggleClass(dragEl, options.ghostClass, true);
+      Sortable.active = this;
+      fallback && this._appendGhost(); // Drag start event
+
+      _dispatchEvent({
+        sortable: this,
+        name: 'start',
+        originalEvent: evt
+      });
+    } else {
+      this._nulling();
+    }
+  },
+  _emulateDragOver: function _emulateDragOver() {
+    if (touchEvt) {
+      this._lastX = touchEvt.clientX;
+      this._lastY = touchEvt.clientY;
+
+      _hideGhostForTarget();
+
+      var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+      var parent = target;
+
+      while (target && target.shadowRoot) {
+        target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+        if (target === parent) break;
+        parent = target;
+      }
+
+      dragEl.parentNode[expando]._isOutsideThisEl(target);
+
+      if (parent) {
+        do {
+          if (parent[expando]) {
+            var inserted = void 0;
+            inserted = parent[expando]._onDragOver({
+              clientX: touchEvt.clientX,
+              clientY: touchEvt.clientY,
+              target: target,
+              rootEl: parent
+            });
+
+            if (inserted && !this.options.dragoverBubble) {
+              break;
+            }
+          }
+
+          target = parent; // store last element
+        }
+        /* jshint boss:true */
+        while (parent = parent.parentNode);
+      }
+
+      _unhideGhostForTarget();
+    }
+  },
+  _onTouchMove: function _onTouchMove(
+  /**TouchEvent*/
+  evt) {
+    if (tapEvt) {
+      var options = this.options,
+          fallbackTolerance = options.fallbackTolerance,
+          fallbackOffset = options.fallbackOffset,
+          touch = evt.touches ? evt.touches[0] : evt,
+          ghostMatrix = ghostEl && matrix(ghostEl, true),
+          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
+          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
+          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
+          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
+          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging
+
+      if (!Sortable.active && !awaitingDragStarted) {
+        if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
+          return;
+        }
+
+        this._onDragStart(evt, true);
+      }
+
+      if (ghostEl) {
+        if (ghostMatrix) {
+          ghostMatrix.e += dx - (lastDx || 0);
+          ghostMatrix.f += dy - (lastDy || 0);
+        } else {
+          ghostMatrix = {
+            a: 1,
+            b: 0,
+            c: 0,
+            d: 1,
+            e: dx,
+            f: dy
+          };
+        }
+
+        var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
+        css(ghostEl, 'webkitTransform', cssMatrix);
+        css(ghostEl, 'mozTransform', cssMatrix);
+        css(ghostEl, 'msTransform', cssMatrix);
+        css(ghostEl, 'transform', cssMatrix);
+        lastDx = dx;
+        lastDy = dy;
+        touchEvt = touch;
+      }
+
+      evt.cancelable && evt.preventDefault();
+    }
+  },
+  _appendGhost: function _appendGhost() {
+    // Bug if using scale(): https://stackoverflow.com/questions/2637058
+    // Not being adjusted for
+    if (!ghostEl) {
+      var container = this.options.fallbackOnBody ? document.body : rootEl,
+          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
+          options = this.options; // Position absolutely
+
+      if (PositionGhostAbsolutely) {
+        // Get relatively positioned parent
+        ghostRelativeParent = container;
+
+        while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
+          ghostRelativeParent = ghostRelativeParent.parentNode;
+        }
+
+        if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
+          if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
+          rect.top += ghostRelativeParent.scrollTop;
+          rect.left += ghostRelativeParent.scrollLeft;
+        } else {
+          ghostRelativeParent = getWindowScrollingElement();
+        }
+
+        ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
+      }
+
+      ghostEl = dragEl.cloneNode(true);
+      toggleClass(ghostEl, options.ghostClass, false);
+      toggleClass(ghostEl, options.fallbackClass, true);
+      toggleClass(ghostEl, options.dragClass, true);
+      css(ghostEl, 'transition', '');
+      css(ghostEl, 'transform', '');
+      css(ghostEl, 'box-sizing', 'border-box');
+      css(ghostEl, 'margin', 0);
+      css(ghostEl, 'top', rect.top);
+      css(ghostEl, 'left', rect.left);
+      css(ghostEl, 'width', rect.width);
+      css(ghostEl, 'height', rect.height);
+      css(ghostEl, 'opacity', '0.8');
+      css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
+      css(ghostEl, 'zIndex', '100000');
+      css(ghostEl, 'pointerEvents', 'none');
+      Sortable.ghost = ghostEl;
+      container.appendChild(ghostEl); // Set transform-origin
+
+      css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
+    }
+  },
+  _onDragStart: function _onDragStart(
+  /**Event*/
+  evt,
+  /**boolean*/
+  fallback) {
+    var _this = this;
+
+    var dataTransfer = evt.dataTransfer;
+    var options = _this.options;
+    pluginEvent('dragStart', this, {
+      evt: evt
+    });
+
+    if (Sortable.eventCanceled) {
+      this._onDrop();
+
+      return;
+    }
+
+    pluginEvent('setupClone', this);
+
+    if (!Sortable.eventCanceled) {
+      cloneEl = clone(dragEl);
+      cloneEl.draggable = false;
+      cloneEl.style['will-change'] = '';
+
+      this._hideClone();
+
+      toggleClass(cloneEl, this.options.chosenClass, false);
+      Sortable.clone = cloneEl;
+    } // #1143: IFrame support workaround
+
+
+    _this.cloneId = _nextTick(function () {
+      pluginEvent('clone', _this);
+      if (Sortable.eventCanceled) return;
+
+      if (!_this.options.removeCloneOnHide) {
+        rootEl.insertBefore(cloneEl, dragEl);
+      }
+
+      _this._hideClone();
+
+      _dispatchEvent({
+        sortable: _this,
+        name: 'clone'
+      });
+    });
+    !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
+
+    if (fallback) {
+      ignoreNextClick = true;
+      _this._loopId = setInterval(_this._emulateDragOver, 50);
+    } else {
+      // Undo what was set in _prepareDragStart before drag started
+      off(document, 'mouseup', _this._onDrop);
+      off(document, 'touchend', _this._onDrop);
+      off(document, 'touchcancel', _this._onDrop);
+
+      if (dataTransfer) {
+        dataTransfer.effectAllowed = 'move';
+        options.setData && options.setData.call(_this, dataTransfer, dragEl);
+      }
+
+      on(document, 'drop', _this); // #1276 fix:
+
+      css(dragEl, 'transform', 'translateZ(0)');
+    }
+
+    awaitingDragStarted = true;
+    _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
+    on(document, 'selectstart', _this);
+    moved = true;
+
+    if (Safari) {
+      css(document.body, 'user-select', 'none');
+    }
+  },
+  // Returns true - if no further action is needed (either inserted or another condition)
+  _onDragOver: function _onDragOver(
+  /**Event*/
+  evt) {
+    var el = this.el,
+        target = evt.target,
+        dragRect,
+        targetRect,
+        revert,
+        options = this.options,
+        group = options.group,
+        activeSortable = Sortable.active,
+        isOwner = activeGroup === group,
+        canSort = options.sort,
+        fromSortable = putSortable || activeSortable,
+        vertical,
+        _this = this,
+        completedFired = false;
+
+    if (_silent) return;
+
+    function dragOverEvent(name, extra) {
+      pluginEvent(name, _this, _objectSpread({
+        evt: evt,
+        isOwner: isOwner,
+        axis: vertical ? 'vertical' : 'horizontal',
+        revert: revert,
+        dragRect: dragRect,
+        targetRect: targetRect,
+        canSort: canSort,
+        fromSortable: fromSortable,
+        target: target,
+        completed: completed,
+        onMove: function onMove(target, after) {
+          return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
+        },
+        changed: changed
+      }, extra));
+    } // Capture animation state
+
+
+    function capture() {
+      dragOverEvent('dragOverAnimationCapture');
+
+      _this.captureAnimationState();
+
+      if (_this !== fromSortable) {
+        fromSortable.captureAnimationState();
+      }
+    } // Return invocation when dragEl is inserted (or completed)
+
+
+    function completed(insertion) {
+      dragOverEvent('dragOverCompleted', {
+        insertion: insertion
+      });
+
+      if (insertion) {
+        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+        if (isOwner) {
+          activeSortable._hideClone();
+        } else {
+          activeSortable._showClone(_this);
+        }
+
+        if (_this !== fromSortable) {
+          // Set ghost class to new sortable's ghost class
+          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
+          toggleClass(dragEl, options.ghostClass, true);
+        }
+
+        if (putSortable !== _this && _this !== Sortable.active) {
+          putSortable = _this;
+        } else if (_this === Sortable.active && putSortable) {
+          putSortable = null;
+        } // Animation
+
+
+        if (fromSortable === _this) {
+          _this._ignoreWhileAnimating = target;
+        }
+
+        _this.animateAll(function () {
+          dragOverEvent('dragOverAnimationComplete');
+          _this._ignoreWhileAnimating = null;
+        });
+
+        if (_this !== fromSortable) {
+          fromSortable.animateAll();
+          fromSortable._ignoreWhileAnimating = null;
+        }
+      } // Null lastTarget if it is not inside a previously swapped element
+
+
+      if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
+        lastTarget = null;
+      } // no bubbling and not fallback
+
+
+      if (!options.dragoverBubble && !evt.rootEl && target !== document) {
+        dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
+
+
+        !insertion && nearestEmptyInsertDetectEvent(evt);
+      }
+
+      !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
+      return completedFired = true;
+    } // Call when dragEl has been inserted
+
+
+    function changed() {
+      newIndex = index(dragEl);
+      newDraggableIndex = index(dragEl, options.draggable);
+
+      _dispatchEvent({
+        sortable: _this,
+        name: 'change',
+        toEl: el,
+        newIndex: newIndex,
+        newDraggableIndex: newDraggableIndex,
+        originalEvent: evt
+      });
+    }
+
+    if (evt.preventDefault !== void 0) {
+      evt.cancelable && evt.preventDefault();
+    }
+
+    target = closest(target, options.draggable, el, true);
+    dragOverEvent('dragOver');
+    if (Sortable.eventCanceled) return completedFired;
+
+    if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
+      return completed(false);
+    }
+
+    ignoreNextClick = false;
+
+    if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
+    : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
+      vertical = this._getDirection(evt, target) === 'vertical';
+      dragRect = getRect(dragEl);
+      dragOverEvent('dragOverValid');
+      if (Sortable.eventCanceled) return completedFired;
+
+      if (revert) {
+        parentEl = rootEl; // actualization
+
+        capture();
+
+        this._hideClone();
+
+        dragOverEvent('revert');
+
+        if (!Sortable.eventCanceled) {
+          if (nextEl) {
+            rootEl.insertBefore(dragEl, nextEl);
+          } else {
+            rootEl.appendChild(dragEl);
+          }
+        }
+
+        return completed(true);
+      }
+
+      var elLastChild = lastChild(el, options.draggable);
+
+      if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
+        // If already at end of list: Do not insert
+        if (elLastChild === dragEl) {
+          return completed(false);
+        } // assign target only if condition is true
+
+
+        if (elLastChild && el === evt.target) {
+          target = elLastChild;
+        }
+
+        if (target) {
+          targetRect = getRect(target);
+        }
+
+        if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
+          capture();
+          el.appendChild(dragEl);
+          parentEl = el; // actualization
+
+          changed();
+          return completed(true);
+        }
+      } else if (target.parentNode === el) {
+        targetRect = getRect(target);
+        var direction = 0,
+            targetBeforeFirstSwap,
+            differentLevel = dragEl.parentNode !== el,
+            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
+            side1 = vertical ? 'top' : 'left',
+            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
+            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
+
+        if (lastTarget !== target) {
+          targetBeforeFirstSwap = targetRect[side1];
+          pastFirstInvertThresh = false;
+          isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
+        }
+
+        direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
+        var sibling;
+
+        if (direction !== 0) {
+          // Check if target is beside dragEl in respective direction (ignoring hidden elements)
+          var dragIndex = index(dragEl);
+
+          do {
+            dragIndex -= direction;
+            sibling = parentEl.children[dragIndex];
+          } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
+        } // If dragEl is already beside target: Do not insert
+
+
+        if (direction === 0 || sibling === target) {
+          return completed(false);
+        }
+
+        lastTarget = target;
+        lastDirection = direction;
+        var nextSibling = target.nextElementSibling,
+            after = false;
+        after = direction === 1;
+
+        var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
+
+        if (moveVector !== false) {
+          if (moveVector === 1 || moveVector === -1) {
+            after = moveVector === 1;
+          }
+
+          _silent = true;
+          setTimeout(_unsilent, 30);
+          capture();
+
+          if (after && !nextSibling) {
+            el.appendChild(dragEl);
+          } else {
+            target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
+          } // Undo chrome's scroll adjustment (has no effect on other browsers)
+
+
+          if (scrolledPastTop) {
+            scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
+          }
+
+          parentEl = dragEl.parentNode; // actualization
+          // must be done before animation
+
+          if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
+            targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
+          }
+
+          changed();
+          return completed(true);
+        }
+      }
+
+      if (el.contains(dragEl)) {
+        return completed(false);
+      }
+    }
+
+    return false;
+  },
+  _ignoreWhileAnimating: null,
+  _offMoveEvents: function _offMoveEvents() {
+    off(document, 'mousemove', this._onTouchMove);
+    off(document, 'touchmove', this._onTouchMove);
+    off(document, 'pointermove', this._onTouchMove);
+    off(document, 'dragover', nearestEmptyInsertDetectEvent);
+    off(document, 'mousemove', nearestEmptyInsertDetectEvent);
+    off(document, 'touchmove', nearestEmptyInsertDetectEvent);
+  },
+  _offUpEvents: function _offUpEvents() {
+    var ownerDocument = this.el.ownerDocument;
+    off(ownerDocument, 'mouseup', this._onDrop);
+    off(ownerDocument, 'touchend', this._onDrop);
+    off(ownerDocument, 'pointerup', this._onDrop);
+    off(ownerDocument, 'touchcancel', this._onDrop);
+    off(document, 'selectstart', this);
+  },
+  _onDrop: function _onDrop(
+  /**Event*/
+  evt) {
+    var el = this.el,
+        options = this.options; // Get the index of the dragged element within its parent
+
+    newIndex = index(dragEl);
+    newDraggableIndex = index(dragEl, options.draggable);
+    pluginEvent('drop', this, {
+      evt: evt
+    });
+    parentEl = dragEl && dragEl.parentNode; // Get again after plugin event
+
+    newIndex = index(dragEl);
+    newDraggableIndex = index(dragEl, options.draggable);
+
+    if (Sortable.eventCanceled) {
+      this._nulling();
+
+      return;
+    }
+
+    awaitingDragStarted = false;
+    isCircumstantialInvert = false;
+    pastFirstInvertThresh = false;
+    clearInterval(this._loopId);
+    clearTimeout(this._dragStartTimer);
+
+    _cancelNextTick(this.cloneId);
+
+    _cancelNextTick(this._dragStartId); // Unbind events
+
+
+    if (this.nativeDraggable) {
+      off(document, 'drop', this);
+      off(el, 'dragstart', this._onDragStart);
+    }
+
+    this._offMoveEvents();
+
+    this._offUpEvents();
+
+    if (Safari) {
+      css(document.body, 'user-select', '');
+    }
+
+    css(dragEl, 'transform', '');
+
+    if (evt) {
+      if (moved) {
+        evt.cancelable && evt.preventDefault();
+        !options.dropBubble && evt.stopPropagation();
+      }
+
+      ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
+
+      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+        // Remove clone(s)
+        cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
+      }
+
+      if (dragEl) {
+        if (this.nativeDraggable) {
+          off(dragEl, 'dragend', this);
+        }
+
+        _disableDraggable(dragEl);
+
+        dragEl.style['will-change'] = ''; // Remove classes
+        // ghostClass is added in dragStarted
+
+        if (moved && !awaitingDragStarted) {
+          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
+        }
+
+        toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
+
+        _dispatchEvent({
+          sortable: this,
+          name: 'unchoose',
+          toEl: parentEl,
+          newIndex: null,
+          newDraggableIndex: null,
+          originalEvent: evt
+        });
+
+        if (rootEl !== parentEl) {
+          if (newIndex >= 0) {
+            // Add event
+            _dispatchEvent({
+              rootEl: parentEl,
+              name: 'add',
+              toEl: parentEl,
+              fromEl: rootEl,
+              originalEvent: evt
+            }); // Remove event
+
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'remove',
+              toEl: parentEl,
+              originalEvent: evt
+            }); // drag from one list and drop into another
+
+
+            _dispatchEvent({
+              rootEl: parentEl,
+              name: 'sort',
+              toEl: parentEl,
+              fromEl: rootEl,
+              originalEvent: evt
+            });
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'sort',
+              toEl: parentEl,
+              originalEvent: evt
+            });
+          }
+
+          putSortable && putSortable.save();
+        } else {
+          if (newIndex !== oldIndex) {
+            if (newIndex >= 0) {
+              // drag & drop within the same list
+              _dispatchEvent({
+                sortable: this,
+                name: 'update',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+
+              _dispatchEvent({
+                sortable: this,
+                name: 'sort',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+            }
+          }
+        }
+
+        if (Sortable.active) {
+          /* jshint eqnull:true */
+          if (newIndex == null || newIndex === -1) {
+            newIndex = oldIndex;
+            newDraggableIndex = oldDraggableIndex;
+          }
+
+          _dispatchEvent({
+            sortable: this,
+            name: 'end',
+            toEl: parentEl,
+            originalEvent: evt
+          }); // Save sorting
+
+
+          this.save();
+        }
+      }
+    }
+
+    this._nulling();
+  },
+  _nulling: function _nulling() {
+    pluginEvent('nulling', this);
+    rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
+    savedInputChecked.forEach(function (el) {
+      el.checked = true;
+    });
+    savedInputChecked.length = lastDx = lastDy = 0;
+  },
+  handleEvent: function handleEvent(
+  /**Event*/
+  evt) {
+    switch (evt.type) {
+      case 'drop':
+      case 'dragend':
+        this._onDrop(evt);
+
+        break;
+
+      case 'dragenter':
+      case 'dragover':
+        if (dragEl) {
+          this._onDragOver(evt);
+
+          _globalDragOver(evt);
+        }
+
+        break;
+
+      case 'selectstart':
+        evt.preventDefault();
+        break;
+    }
+  },
+
+  /**
+   * Serializes the item into an array of string.
+   * @returns {String[]}
+   */
+  toArray: function toArray() {
+    var order = [],
+        el,
+        children = this.el.children,
+        i = 0,
+        n = children.length,
+        options = this.options;
+
+    for (; i < n; i++) {
+      el = children[i];
+
+      if (closest(el, options.draggable, this.el, false)) {
+        order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
+      }
+    }
+
+    return order;
+  },
+
+  /**
+   * Sorts the elements according to the array.
+   * @param  {String[]}  order  order of the items
+   */
+  sort: function sort(order) {
+    var items = {},
+        rootEl = this.el;
+    this.toArray().forEach(function (id, i) {
+      var el = rootEl.children[i];
+
+      if (closest(el, this.options.draggable, rootEl, false)) {
+        items[id] = el;
+      }
+    }, this);
+    order.forEach(function (id) {
+      if (items[id]) {
+        rootEl.removeChild(items[id]);
+        rootEl.appendChild(items[id]);
+      }
+    });
+  },
+
+  /**
+   * Save the current sorting
+   */
+  save: function save() {
+    var store = this.options.store;
+    store && store.set && store.set(this);
+  },
+
+  /**
+   * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+   * @param   {HTMLElement}  el
+   * @param   {String}       [selector]  default: `options.draggable`
+   * @returns {HTMLElement|null}
+   */
+  closest: function closest$1(el, selector) {
+    return closest(el, selector || this.options.draggable, this.el, false);
+  },
+
+  /**
+   * Set/get option
+   * @param   {string} name
+   * @param   {*}      [value]
+   * @returns {*}
+   */
+  option: function option(name, value) {
+    var options = this.options;
+
+    if (value === void 0) {
+      return options[name];
+    } else {
+      var modifiedValue = PluginManager.modifyOption(this, name, value);
+
+      if (typeof modifiedValue !== 'undefined') {
+        options[name] = modifiedValue;
+      } else {
+        options[name] = value;
+      }
+
+      if (name === 'group') {
+        _prepareGroup(options);
+      }
+    }
+  },
+
+  /**
+   * Destroy
+   */
+  destroy: function destroy() {
+    pluginEvent('destroy', this);
+    var el = this.el;
+    el[expando] = null;
+    off(el, 'mousedown', this._onTapStart);
+    off(el, 'touchstart', this._onTapStart);
+    off(el, 'pointerdown', this._onTapStart);
+
+    if (this.nativeDraggable) {
+      off(el, 'dragover', this);
+      off(el, 'dragenter', this);
+    } // Remove draggable attributes
+
+
+    Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
+      el.removeAttribute('draggable');
+    });
+
+    this._onDrop();
+
+    this._disableDelayedDragEvents();
+
+    sortables.splice(sortables.indexOf(this.el), 1);
+    this.el = el = null;
+  },
+  _hideClone: function _hideClone() {
+    if (!cloneHidden) {
+      pluginEvent('hideClone', this);
+      if (Sortable.eventCanceled) return;
+      css(cloneEl, 'display', 'none');
+
+      if (this.options.removeCloneOnHide && cloneEl.parentNode) {
+        cloneEl.parentNode.removeChild(cloneEl);
+      }
+
+      cloneHidden = true;
+    }
+  },
+  _showClone: function _showClone(putSortable) {
+    if (putSortable.lastPutMode !== 'clone') {
+      this._hideClone();
+
+      return;
+    }
+
+    if (cloneHidden) {
+      pluginEvent('showClone', this);
+      if (Sortable.eventCanceled) return; // show clone at dragEl or original position
+
+      if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
+        rootEl.insertBefore(cloneEl, dragEl);
+      } else if (nextEl) {
+        rootEl.insertBefore(cloneEl, nextEl);
+      } else {
+        rootEl.appendChild(cloneEl);
+      }
+
+      if (this.options.group.revertClone) {
+        this.animate(dragEl, cloneEl);
+      }
+
+      css(cloneEl, 'display', '');
+      cloneHidden = false;
+    }
+  }
+};
+
+function _globalDragOver(
+/**Event*/
+evt) {
+  if (evt.dataTransfer) {
+    evt.dataTransfer.dropEffect = 'move';
+  }
+
+  evt.cancelable && evt.preventDefault();
+}
+
+function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
+  var evt,
+      sortable = fromEl[expando],
+      onMoveFn = sortable.options.onMove,
+      retVal; // Support for new CustomEvent feature
+
+  if (window.CustomEvent && !IE11OrLess && !Edge) {
+    evt = new CustomEvent('move', {
+      bubbles: true,
+      cancelable: true
+    });
+  } else {
+    evt = document.createEvent('Event');
+    evt.initEvent('move', true, true);
+  }
+
+  evt.to = toEl;
+  evt.from = fromEl;
+  evt.dragged = dragEl;
+  evt.draggedRect = dragRect;
+  evt.related = targetEl || toEl;
+  evt.relatedRect = targetRect || getRect(toEl);
+  evt.willInsertAfter = willInsertAfter;
+  evt.originalEvent = originalEvent;
+  fromEl.dispatchEvent(evt);
+
+  if (onMoveFn) {
+    retVal = onMoveFn.call(sortable, evt, originalEvent);
+  }
+
+  return retVal;
+}
+
+function _disableDraggable(el) {
+  el.draggable = false;
+}
+
+function _unsilent() {
+  _silent = false;
+}
+
+function _ghostIsLast(evt, vertical, sortable) {
+  var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
+  var spacer = 10;
+  return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
+}
+
+function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
+  var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
+      targetLength = vertical ? targetRect.height : targetRect.width,
+      targetS1 = vertical ? targetRect.top : targetRect.left,
+      targetS2 = vertical ? targetRect.bottom : targetRect.right,
+      invert = false;
+
+  if (!invertSwap) {
+    // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
+    if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
+      // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
+      // check if past first invert threshold on side opposite of lastDirection
+      if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
+        // past first invert threshold, do not restrict inverted threshold to dragEl shadow
+        pastFirstInvertThresh = true;
+      }
+
+      if (!pastFirstInvertThresh) {
+        // dragEl shadow (target move distance shadow)
+        if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
+        : mouseOnAxis > targetS2 - targetMoveDistance) {
+          return -lastDirection;
+        }
+      } else {
+        invert = true;
+      }
+    } else {
+      // Regular
+      if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
+        return _getInsertDirection(target);
+      }
+    }
+  }
+
+  invert = invert || invertSwap;
+
+  if (invert) {
+    // Invert of regular
+    if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
+      return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
+    }
+  }
+
+  return 0;
+}
+/**
+ * Gets the direction dragEl must be swapped relative to target in order to make it
+ * seem that dragEl has been "inserted" into that element's position
+ * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
+ * @return {Number}                   Direction dragEl must be swapped
+ */
+
+
+function _getInsertDirection(target) {
+  if (index(dragEl) < index(target)) {
+    return 1;
+  } else {
+    return -1;
+  }
+}
+/**
+ * Generate id
+ * @param   {HTMLElement} el
+ * @returns {String}
+ * @private
+ */
+
+
+function _generateId(el) {
+  var str = el.tagName + el.className + el.src + el.href + el.textContent,
+      i = str.length,
+      sum = 0;
+
+  while (i--) {
+    sum += str.charCodeAt(i);
+  }
+
+  return sum.toString(36);
+}
+
+function _saveInputCheckedState(root) {
+  savedInputChecked.length = 0;
+  var inputs = root.getElementsByTagName('input');
+  var idx = inputs.length;
+
+  while (idx--) {
+    var el = inputs[idx];
+    el.checked && savedInputChecked.push(el);
+  }
+}
+
+function _nextTick(fn) {
+  return setTimeout(fn, 0);
+}
+
+function _cancelNextTick(id) {
+  return clearTimeout(id);
+} // Fixed #973:
+
+
+if (documentExists) {
+  on(document, 'touchmove', function (evt) {
+    if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
+      evt.preventDefault();
+    }
+  });
+} // Export utils
+
+
+Sortable.utils = {
+  on: on,
+  off: off,
+  css: css,
+  find: find,
+  is: function is(el, selector) {
+    return !!closest(el, selector, el, false);
+  },
+  extend: extend,
+  throttle: throttle,
+  closest: closest,
+  toggleClass: toggleClass,
+  clone: clone,
+  index: index,
+  nextTick: _nextTick,
+  cancelNextTick: _cancelNextTick,
+  detectDirection: _detectDirection,
+  getChild: getChild
+};
+/**
+ * Get the Sortable instance of an element
+ * @param  {HTMLElement} element The element
+ * @return {Sortable|undefined}         The instance of Sortable
+ */
+
+Sortable.get = function (element) {
+  return element[expando];
+};
+/**
+ * Mount a plugin to Sortable
+ * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
+ */
+
+
+Sortable.mount = function () {
+  for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
+    plugins[_key] = arguments[_key];
+  }
+
+  if (plugins[0].constructor === Array) plugins = plugins[0];
+  plugins.forEach(function (plugin) {
+    if (!plugin.prototype || !plugin.prototype.constructor) {
+      throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
+    }
+
+    if (plugin.utils) Sortable.utils = _objectSpread({}, Sortable.utils, plugin.utils);
+    PluginManager.mount(plugin);
+  });
+};
+/**
+ * Create sortable instance
+ * @param {HTMLElement}  el
+ * @param {Object}      [options]
+ */
+
+
+Sortable.create = function (el, options) {
+  return new Sortable(el, options);
+}; // Export
+
+
+Sortable.version = version;
+
+var autoScrolls = [],
+    scrollEl,
+    scrollRootEl,
+    scrolling = false,
+    lastAutoScrollX,
+    lastAutoScrollY,
+    touchEvt$1,
+    pointerElemChangedInterval;
+
+function AutoScrollPlugin() {
+  function AutoScroll() {
+    this.defaults = {
+      scroll: true,
+      scrollSensitivity: 30,
+      scrollSpeed: 10,
+      bubbleScroll: true
+    }; // Bind all private methods
+
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    }
+  }
+
+  AutoScroll.prototype = {
+    dragStarted: function dragStarted(_ref) {
+      var originalEvent = _ref.originalEvent;
+
+      if (this.sortable.nativeDraggable) {
+        on(document, 'dragover', this._handleAutoScroll);
+      } else {
+        if (this.options.supportPointer) {
+          on(document, 'pointermove', this._handleFallbackAutoScroll);
+        } else if (originalEvent.touches) {
+          on(document, 'touchmove', this._handleFallbackAutoScroll);
+        } else {
+          on(document, 'mousemove', this._handleFallbackAutoScroll);
+        }
+      }
+    },
+    dragOverCompleted: function dragOverCompleted(_ref2) {
+      var originalEvent = _ref2.originalEvent;
+
+      // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
+      if (!this.options.dragOverBubble && !originalEvent.rootEl) {
+        this._handleAutoScroll(originalEvent);
+      }
+    },
+    drop: function drop() {
+      if (this.sortable.nativeDraggable) {
+        off(document, 'dragover', this._handleAutoScroll);
+      } else {
+        off(document, 'pointermove', this._handleFallbackAutoScroll);
+        off(document, 'touchmove', this._handleFallbackAutoScroll);
+        off(document, 'mousemove', this._handleFallbackAutoScroll);
+      }
+
+      clearPointerElemChangedInterval();
+      clearAutoScrolls();
+      cancelThrottle();
+    },
+    nulling: function nulling() {
+      touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
+      autoScrolls.length = 0;
+    },
+    _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
+      this._handleAutoScroll(evt, true);
+    },
+    _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
+      var _this = this;
+
+      var x = (evt.touches ? evt.touches[0] : evt).clientX,
+          y = (evt.touches ? evt.touches[0] : evt).clientY,
+          elem = document.elementFromPoint(x, y);
+      touchEvt$1 = evt; // IE does not seem to have native autoscroll,
+      // Edge's autoscroll seems too conditional,
+      // MACOS Safari does not have autoscroll,
+      // Firefox and Chrome are good
+
+      if (fallback || Edge || IE11OrLess || Safari) {
+        autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
+
+        var ogElemScroller = getParentAutoScrollElement(elem, true);
+
+        if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
+          pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
+
+          pointerElemChangedInterval = setInterval(function () {
+            var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
+
+            if (newElem !== ogElemScroller) {
+              ogElemScroller = newElem;
+              clearAutoScrolls();
+            }
+
+            autoScroll(evt, _this.options, newElem, fallback);
+          }, 10);
+          lastAutoScrollX = x;
+          lastAutoScrollY = y;
+        }
+      } else {
+        // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
+        if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
+          clearAutoScrolls();
+          return;
+        }
+
+        autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
+      }
+    }
+  };
+  return _extends(AutoScroll, {
+    pluginName: 'scroll',
+    initializeByDefault: true
+  });
+}
+
+function clearAutoScrolls() {
+  autoScrolls.forEach(function (autoScroll) {
+    clearInterval(autoScroll.pid);
+  });
+  autoScrolls = [];
+}
+
+function clearPointerElemChangedInterval() {
+  clearInterval(pointerElemChangedInterval);
+}
+
+var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
+  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+  if (!options.scroll) return;
+  var x = (evt.touches ? evt.touches[0] : evt).clientX,
+      y = (evt.touches ? evt.touches[0] : evt).clientY,
+      sens = options.scrollSensitivity,
+      speed = options.scrollSpeed,
+      winScroller = getWindowScrollingElement();
+  var scrollThisInstance = false,
+      scrollCustomFn; // New scroll root, set scrollEl
+
+  if (scrollRootEl !== rootEl) {
+    scrollRootEl = rootEl;
+    clearAutoScrolls();
+    scrollEl = options.scroll;
+    scrollCustomFn = options.scrollFn;
+
+    if (scrollEl === true) {
+      scrollEl = getParentAutoScrollElement(rootEl, true);
+    }
+  }
+
+  var layersOut = 0;
+  var currentParent = scrollEl;
+
+  do {
+    var el = currentParent,
+        rect = getRect(el),
+        top = rect.top,
+        bottom = rect.bottom,
+        left = rect.left,
+        right = rect.right,
+        width = rect.width,
+        height = rect.height,
+        canScrollX = void 0,
+        canScrollY = void 0,
+        scrollWidth = el.scrollWidth,
+        scrollHeight = el.scrollHeight,
+        elCSS = css(el),
+        scrollPosX = el.scrollLeft,
+        scrollPosY = el.scrollTop;
+
+    if (el === winScroller) {
+      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
+      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
+    } else {
+      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
+      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
+    }
+
+    var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
+    var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
+
+    if (!autoScrolls[layersOut]) {
+      for (var i = 0; i <= layersOut; i++) {
+        if (!autoScrolls[i]) {
+          autoScrolls[i] = {};
+        }
+      }
+    }
+
+    if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
+      autoScrolls[layersOut].el = el;
+      autoScrolls[layersOut].vx = vx;
+      autoScrolls[layersOut].vy = vy;
+      clearInterval(autoScrolls[layersOut].pid);
+
+      if (vx != 0 || vy != 0) {
+        scrollThisInstance = true;
+        /* jshint loopfunc:true */
+
+        autoScrolls[layersOut].pid = setInterval(function () {
+          // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
+          if (isFallback && this.layer === 0) {
+            Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
+
+          }
+
+          var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
+          var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
+
+          if (typeof scrollCustomFn === 'function') {
+            if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
+              return;
+            }
+          }
+
+          scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
+        }.bind({
+          layer: layersOut
+        }), 24);
+      }
+    }
+
+    layersOut++;
+  } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
+
+  scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
+}, 30);
+
+var drop = function drop(_ref) {
+  var originalEvent = _ref.originalEvent,
+      putSortable = _ref.putSortable,
+      dragEl = _ref.dragEl,
+      activeSortable = _ref.activeSortable,
+      dispatchSortableEvent = _ref.dispatchSortableEvent,
+      hideGhostForTarget = _ref.hideGhostForTarget,
+      unhideGhostForTarget = _ref.unhideGhostForTarget;
+  if (!originalEvent) return;
+  var toSortable = putSortable || activeSortable;
+  hideGhostForTarget();
+  var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
+  var target = document.elementFromPoint(touch.clientX, touch.clientY);
+  unhideGhostForTarget();
+
+  if (toSortable && !toSortable.el.contains(target)) {
+    dispatchSortableEvent('spill');
+    this.onSpill({
+      dragEl: dragEl,
+      putSortable: putSortable
+    });
+  }
+};
+
+function Revert() {}
+
+Revert.prototype = {
+  startIndex: null,
+  dragStart: function dragStart(_ref2) {
+    var oldDraggableIndex = _ref2.oldDraggableIndex;
+    this.startIndex = oldDraggableIndex;
+  },
+  onSpill: function onSpill(_ref3) {
+    var dragEl = _ref3.dragEl,
+        putSortable = _ref3.putSortable;
+    this.sortable.captureAnimationState();
+
+    if (putSortable) {
+      putSortable.captureAnimationState();
+    }
+
+    var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
+
+    if (nextSibling) {
+      this.sortable.el.insertBefore(dragEl, nextSibling);
+    } else {
+      this.sortable.el.appendChild(dragEl);
+    }
+
+    this.sortable.animateAll();
+
+    if (putSortable) {
+      putSortable.animateAll();
+    }
+  },
+  drop: drop
+};
+
+_extends(Revert, {
+  pluginName: 'revertOnSpill'
+});
+
+function Remove() {}
+
+Remove.prototype = {
+  onSpill: function onSpill(_ref4) {
+    var dragEl = _ref4.dragEl,
+        putSortable = _ref4.putSortable;
+    var parentSortable = putSortable || this.sortable;
+    parentSortable.captureAnimationState();
+    dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
+    parentSortable.animateAll();
+  },
+  drop: drop
+};
+
+_extends(Remove, {
+  pluginName: 'removeOnSpill'
+});
+
+var lastSwapEl;
+
+function SwapPlugin() {
+  function Swap() {
+    this.defaults = {
+      swapClass: 'sortable-swap-highlight'
+    };
+  }
+
+  Swap.prototype = {
+    dragStart: function dragStart(_ref) {
+      var dragEl = _ref.dragEl;
+      lastSwapEl = dragEl;
+    },
+    dragOverValid: function dragOverValid(_ref2) {
+      var completed = _ref2.completed,
+          target = _ref2.target,
+          onMove = _ref2.onMove,
+          activeSortable = _ref2.activeSortable,
+          changed = _ref2.changed,
+          cancel = _ref2.cancel;
+      if (!activeSortable.options.swap) return;
+      var el = this.sortable.el,
+          options = this.options;
+
+      if (target && target !== el) {
+        var prevSwapEl = lastSwapEl;
+
+        if (onMove(target) !== false) {
+          toggleClass(target, options.swapClass, true);
+          lastSwapEl = target;
+        } else {
+          lastSwapEl = null;
+        }
+
+        if (prevSwapEl && prevSwapEl !== lastSwapEl) {
+          toggleClass(prevSwapEl, options.swapClass, false);
+        }
+      }
+
+      changed();
+      completed(true);
+      cancel();
+    },
+    drop: function drop(_ref3) {
+      var activeSortable = _ref3.activeSortable,
+          putSortable = _ref3.putSortable,
+          dragEl = _ref3.dragEl;
+      var toSortable = putSortable || this.sortable;
+      var options = this.options;
+      lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
+
+      if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
+        if (dragEl !== lastSwapEl) {
+          toSortable.captureAnimationState();
+          if (toSortable !== activeSortable) activeSortable.captureAnimationState();
+          swapNodes(dragEl, lastSwapEl);
+          toSortable.animateAll();
+          if (toSortable !== activeSortable) activeSortable.animateAll();
+        }
+      }
+    },
+    nulling: function nulling() {
+      lastSwapEl = null;
+    }
+  };
+  return _extends(Swap, {
+    pluginName: 'swap',
+    eventProperties: function eventProperties() {
+      return {
+        swapItem: lastSwapEl
+      };
+    }
+  });
+}
+
+function swapNodes(n1, n2) {
+  var p1 = n1.parentNode,
+      p2 = n2.parentNode,
+      i1,
+      i2;
+  if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
+  i1 = index(n1);
+  i2 = index(n2);
+
+  if (p1.isEqualNode(p2) && i1 < i2) {
+    i2++;
+  }
+
+  p1.insertBefore(n2, p1.children[i1]);
+  p2.insertBefore(n1, p2.children[i2]);
+}
+
+var multiDragElements = [],
+    multiDragClones = [],
+    lastMultiDragSelect,
+    // for selection with modifier key down (SHIFT)
+multiDragSortable,
+    initialFolding = false,
+    // Initial multi-drag fold when drag started
+folding = false,
+    // Folding any other time
+dragStarted = false,
+    dragEl$1,
+    clonesFromRect,
+    clonesHidden;
+
+function MultiDragPlugin() {
+  function MultiDrag(sortable) {
+    // Bind all private methods
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    }
+
+    if (sortable.options.supportPointer) {
+      on(document, 'pointerup', this._deselectMultiDrag);
+    } else {
+      on(document, 'mouseup', this._deselectMultiDrag);
+      on(document, 'touchend', this._deselectMultiDrag);
+    }
+
+    on(document, 'keydown', this._checkKeyDown);
+    on(document, 'keyup', this._checkKeyUp);
+    this.defaults = {
+      selectedClass: 'sortable-selected',
+      multiDragKey: null,
+      setData: function setData(dataTransfer, dragEl) {
+        var data = '';
+
+        if (multiDragElements.length && multiDragSortable === sortable) {
+          multiDragElements.forEach(function (multiDragElement, i) {
+            data += (!i ? '' : ', ') + multiDragElement.textContent;
+          });
+        } else {
+          data = dragEl.textContent;
+        }
+
+        dataTransfer.setData('Text', data);
+      }
+    };
+  }
+
+  MultiDrag.prototype = {
+    multiDragKeyDown: false,
+    isMultiDrag: false,
+    delayStartGlobal: function delayStartGlobal(_ref) {
+      var dragged = _ref.dragEl;
+      dragEl$1 = dragged;
+    },
+    delayEnded: function delayEnded() {
+      this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
+    },
+    setupClone: function setupClone(_ref2) {
+      var sortable = _ref2.sortable,
+          cancel = _ref2.cancel;
+      if (!this.isMultiDrag) return;
+
+      for (var i = 0; i < multiDragElements.length; i++) {
+        multiDragClones.push(clone(multiDragElements[i]));
+        multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
+        multiDragClones[i].draggable = false;
+        multiDragClones[i].style['will-change'] = '';
+        toggleClass(multiDragClones[i], this.options.selectedClass, false);
+        multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
+      }
+
+      sortable._hideClone();
+
+      cancel();
+    },
+    clone: function clone(_ref3) {
+      var sortable = _ref3.sortable,
+          rootEl = _ref3.rootEl,
+          dispatchSortableEvent = _ref3.dispatchSortableEvent,
+          cancel = _ref3.cancel;
+      if (!this.isMultiDrag) return;
+
+      if (!this.options.removeCloneOnHide) {
+        if (multiDragElements.length && multiDragSortable === sortable) {
+          insertMultiDragClones(true, rootEl);
+          dispatchSortableEvent('clone');
+          cancel();
+        }
+      }
+    },
+    showClone: function showClone(_ref4) {
+      var cloneNowShown = _ref4.cloneNowShown,
+          rootEl = _ref4.rootEl,
+          cancel = _ref4.cancel;
+      if (!this.isMultiDrag) return;
+      insertMultiDragClones(false, rootEl);
+      multiDragClones.forEach(function (clone) {
+        css(clone, 'display', '');
+      });
+      cloneNowShown();
+      clonesHidden = false;
+      cancel();
+    },
+    hideClone: function hideClone(_ref5) {
+      var _this = this;
+
+      var sortable = _ref5.sortable,
+          cloneNowHidden = _ref5.cloneNowHidden,
+          cancel = _ref5.cancel;
+      if (!this.isMultiDrag) return;
+      multiDragClones.forEach(function (clone) {
+        css(clone, 'display', 'none');
+
+        if (_this.options.removeCloneOnHide && clone.parentNode) {
+          clone.parentNode.removeChild(clone);
+        }
+      });
+      cloneNowHidden();
+      clonesHidden = true;
+      cancel();
+    },
+    dragStartGlobal: function dragStartGlobal(_ref6) {
+      var sortable = _ref6.sortable;
+
+      if (!this.isMultiDrag && multiDragSortable) {
+        multiDragSortable.multiDrag._deselectMultiDrag();
+      }
+
+      multiDragElements.forEach(function (multiDragElement) {
+        multiDragElement.sortableIndex = index(multiDragElement);
+      }); // Sort multi-drag elements
+
+      multiDragElements = multiDragElements.sort(function (a, b) {
+        return a.sortableIndex - b.sortableIndex;
+      });
+      dragStarted = true;
+    },
+    dragStarted: function dragStarted(_ref7) {
+      var _this2 = this;
+
+      var sortable = _ref7.sortable;
+      if (!this.isMultiDrag) return;
+
+      if (this.options.sort) {
+        // Capture rects,
+        // hide multi drag elements (by positioning them absolute),
+        // set multi drag elements rects to dragRect,
+        // show multi drag elements,
+        // animate to rects,
+        // unset rects & remove from DOM
+        sortable.captureAnimationState();
+
+        if (this.options.animation) {
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            css(multiDragElement, 'position', 'absolute');
+          });
+          var dragRect = getRect(dragEl$1, false, true, true);
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            setRect(multiDragElement, dragRect);
+          });
+          folding = true;
+          initialFolding = true;
+        }
+      }
+
+      sortable.animateAll(function () {
+        folding = false;
+        initialFolding = false;
+
+        if (_this2.options.animation) {
+          multiDragElements.forEach(function (multiDragElement) {
+            unsetRect(multiDragElement);
+          });
+        } // Remove all auxiliary multidrag items from el, if sorting enabled
+
+
+        if (_this2.options.sort) {
+          removeMultiDragElements();
+        }
+      });
+    },
+    dragOver: function dragOver(_ref8) {
+      var target = _ref8.target,
+          completed = _ref8.completed,
+          cancel = _ref8.cancel;
+
+      if (folding && ~multiDragElements.indexOf(target)) {
+        completed(false);
+        cancel();
+      }
+    },
+    revert: function revert(_ref9) {
+      var fromSortable = _ref9.fromSortable,
+          rootEl = _ref9.rootEl,
+          sortable = _ref9.sortable,
+          dragRect = _ref9.dragRect;
+
+      if (multiDragElements.length > 1) {
+        // Setup unfold animation
+        multiDragElements.forEach(function (multiDragElement) {
+          sortable.addAnimationState({
+            target: multiDragElement,
+            rect: folding ? getRect(multiDragElement) : dragRect
+          });
+          unsetRect(multiDragElement);
+          multiDragElement.fromRect = dragRect;
+          fromSortable.removeAnimationState(multiDragElement);
+        });
+        folding = false;
+        insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
+      }
+    },
+    dragOverCompleted: function dragOverCompleted(_ref10) {
+      var sortable = _ref10.sortable,
+          isOwner = _ref10.isOwner,
+          insertion = _ref10.insertion,
+          activeSortable = _ref10.activeSortable,
+          parentEl = _ref10.parentEl,
+          putSortable = _ref10.putSortable;
+      var options = this.options;
+
+      if (insertion) {
+        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+        if (isOwner) {
+          activeSortable._hideClone();
+        }
+
+        initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location
+
+        if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
+          // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
+          var dragRectAbsolute = getRect(dragEl$1, false, true, true);
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
+            // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
+
+            parentEl.appendChild(multiDragElement);
+          });
+          folding = true;
+        } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
+
+
+        if (!isOwner) {
+          // Only remove if not folding (folding will remove them anyways)
+          if (!folding) {
+            removeMultiDragElements();
+          }
+
+          if (multiDragElements.length > 1) {
+            var clonesHiddenBefore = clonesHidden;
+
+            activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden
+
+
+            if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
+              multiDragClones.forEach(function (clone) {
+                activeSortable.addAnimationState({
+                  target: clone,
+                  rect: clonesFromRect
+                });
+                clone.fromRect = clonesFromRect;
+                clone.thisAnimationDuration = null;
+              });
+            }
+          } else {
+            activeSortable._showClone(sortable);
+          }
+        }
+      }
+    },
+    dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
+      var dragRect = _ref11.dragRect,
+          isOwner = _ref11.isOwner,
+          activeSortable = _ref11.activeSortable;
+      multiDragElements.forEach(function (multiDragElement) {
+        multiDragElement.thisAnimationDuration = null;
+      });
+
+      if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
+        clonesFromRect = _extends({}, dragRect);
+        var dragMatrix = matrix(dragEl$1, true);
+        clonesFromRect.top -= dragMatrix.f;
+        clonesFromRect.left -= dragMatrix.e;
+      }
+    },
+    dragOverAnimationComplete: function dragOverAnimationComplete() {
+      if (folding) {
+        folding = false;
+        removeMultiDragElements();
+      }
+    },
+    drop: function drop(_ref12) {
+      var evt = _ref12.originalEvent,
+          rootEl = _ref12.rootEl,
+          parentEl = _ref12.parentEl,
+          sortable = _ref12.sortable,
+          dispatchSortableEvent = _ref12.dispatchSortableEvent,
+          oldIndex = _ref12.oldIndex,
+          putSortable = _ref12.putSortable;
+      var toSortable = putSortable || this.sortable;
+      if (!evt) return;
+      var options = this.options,
+          children = parentEl.children; // Multi-drag selection
+
+      if (!dragStarted) {
+        if (options.multiDragKey && !this.multiDragKeyDown) {
+          this._deselectMultiDrag();
+        }
+
+        toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
+
+        if (!~multiDragElements.indexOf(dragEl$1)) {
+          multiDragElements.push(dragEl$1);
+          dispatchEvent({
+            sortable: sortable,
+            rootEl: rootEl,
+            name: 'select',
+            targetEl: dragEl$1,
+            originalEvt: evt
+          }); // Modifier activated, select from last to dragEl
+
+          if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
+            var lastIndex = index(lastMultiDragSelect),
+                currentIndex = index(dragEl$1);
+
+            if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
+              // Must include lastMultiDragSelect (select it), in case modified selection from no selection
+              // (but previous selection existed)
+              var n, i;
+
+              if (currentIndex > lastIndex) {
+                i = lastIndex;
+                n = currentIndex;
+              } else {
+                i = currentIndex;
+                n = lastIndex + 1;
+              }
+
+              for (; i < n; i++) {
+                if (~multiDragElements.indexOf(children[i])) continue;
+                toggleClass(children[i], options.selectedClass, true);
+                multiDragElements.push(children[i]);
+                dispatchEvent({
+                  sortable: sortable,
+                  rootEl: rootEl,
+                  name: 'select',
+                  targetEl: children[i],
+                  originalEvt: evt
+                });
+              }
+            }
+          } else {
+            lastMultiDragSelect = dragEl$1;
+          }
+
+          multiDragSortable = toSortable;
+        } else {
+          multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
+          lastMultiDragSelect = null;
+          dispatchEvent({
+            sortable: sortable,
+            rootEl: rootEl,
+            name: 'deselect',
+            targetEl: dragEl$1,
+            originalEvt: evt
+          });
+        }
+      } // Multi-drag drop
+
+
+      if (dragStarted && this.isMultiDrag) {
+        // Do not "unfold" after around dragEl if reverted
+        if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
+          var dragRect = getRect(dragEl$1),
+              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
+          if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
+          toSortable.captureAnimationState();
+
+          if (!initialFolding) {
+            if (options.animation) {
+              dragEl$1.fromRect = dragRect;
+              multiDragElements.forEach(function (multiDragElement) {
+                multiDragElement.thisAnimationDuration = null;
+
+                if (multiDragElement !== dragEl$1) {
+                  var rect = folding ? getRect(multiDragElement) : dragRect;
+                  multiDragElement.fromRect = rect; // Prepare unfold animation
+
+                  toSortable.addAnimationState({
+                    target: multiDragElement,
+                    rect: rect
+                  });
+                }
+              });
+            } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
+            // properly they must all be removed
+
+
+            removeMultiDragElements();
+            multiDragElements.forEach(function (multiDragElement) {
+              if (children[multiDragIndex]) {
+                parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
+              } else {
+                parentEl.appendChild(multiDragElement);
+              }
+
+              multiDragIndex++;
+            }); // If initial folding is done, the elements may have changed position because they are now
+            // unfolding around dragEl, even though dragEl may not have his index changed, so update event
+            // must be fired here as Sortable will not.
+
+            if (oldIndex === index(dragEl$1)) {
+              var update = false;
+              multiDragElements.forEach(function (multiDragElement) {
+                if (multiDragElement.sortableIndex !== index(multiDragElement)) {
+                  update = true;
+                  return;
+                }
+              });
+
+              if (update) {
+                dispatchSortableEvent('update');
+              }
+            }
+          } // Must be done after capturing individual rects (scroll bar)
+
+
+          multiDragElements.forEach(function (multiDragElement) {
+            unsetRect(multiDragElement);
+          });
+          toSortable.animateAll();
+        }
+
+        multiDragSortable = toSortable;
+      } // Remove clones if necessary
+
+
+      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+        multiDragClones.forEach(function (clone) {
+          clone.parentNode && clone.parentNode.removeChild(clone);
+        });
+      }
+    },
+    nullingGlobal: function nullingGlobal() {
+      this.isMultiDrag = dragStarted = false;
+      multiDragClones.length = 0;
+    },
+    destroyGlobal: function destroyGlobal() {
+      this._deselectMultiDrag();
+
+      off(document, 'pointerup', this._deselectMultiDrag);
+      off(document, 'mouseup', this._deselectMultiDrag);
+      off(document, 'touchend', this._deselectMultiDrag);
+      off(document, 'keydown', this._checkKeyDown);
+      off(document, 'keyup', this._checkKeyUp);
+    },
+    _deselectMultiDrag: function _deselectMultiDrag(evt) {
+      if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable
+
+      if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable
+
+      if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click
+
+      if (evt && evt.button !== 0) return;
+
+      while (multiDragElements.length) {
+        var el = multiDragElements[0];
+        toggleClass(el, this.options.selectedClass, false);
+        multiDragElements.shift();
+        dispatchEvent({
+          sortable: this.sortable,
+          rootEl: this.sortable.el,
+          name: 'deselect',
+          targetEl: el,
+          originalEvt: evt
+        });
+      }
+    },
+    _checkKeyDown: function _checkKeyDown(evt) {
+      if (evt.key === this.options.multiDragKey) {
+        this.multiDragKeyDown = true;
+      }
+    },
+    _checkKeyUp: function _checkKeyUp(evt) {
+      if (evt.key === this.options.multiDragKey) {
+        this.multiDragKeyDown = false;
+      }
+    }
+  };
+  return _extends(MultiDrag, {
+    // Static methods & properties
+    pluginName: 'multiDrag',
+    utils: {
+      /**
+       * Selects the provided multi-drag item
+       * @param  {HTMLElement} el    The element to be selected
+       */
+      select: function select(el) {
+        var sortable = el.parentNode[expando];
+        if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
+
+        if (multiDragSortable && multiDragSortable !== sortable) {
+          multiDragSortable.multiDrag._deselectMultiDrag();
+
+          multiDragSortable = sortable;
+        }
+
+        toggleClass(el, sortable.options.selectedClass, true);
+        multiDragElements.push(el);
+      },
+
+      /**
+       * Deselects the provided multi-drag item
+       * @param  {HTMLElement} el    The element to be deselected
+       */
+      deselect: function deselect(el) {
+        var sortable = el.parentNode[expando],
+            index = multiDragElements.indexOf(el);
+        if (!sortable || !sortable.options.multiDrag || !~index) return;
+        toggleClass(el, sortable.options.selectedClass, false);
+        multiDragElements.splice(index, 1);
+      }
+    },
+    eventProperties: function eventProperties() {
+      var _this3 = this;
+
+      var oldIndicies = [],
+          newIndicies = [];
+      multiDragElements.forEach(function (multiDragElement) {
+        oldIndicies.push({
+          multiDragElement: multiDragElement,
+          index: multiDragElement.sortableIndex
+        }); // multiDragElements will already be sorted if folding
+
+        var newIndex;
+
+        if (folding && multiDragElement !== dragEl$1) {
+          newIndex = -1;
+        } else if (folding) {
+          newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
+        } else {
+          newIndex = index(multiDragElement);
+        }
+
+        newIndicies.push({
+          multiDragElement: multiDragElement,
+          index: newIndex
+        });
+      });
+      return {
+        items: _toConsumableArray(multiDragElements),
+        clones: [].concat(multiDragClones),
+        oldIndicies: oldIndicies,
+        newIndicies: newIndicies
+      };
+    },
+    optionListeners: {
+      multiDragKey: function multiDragKey(key) {
+        key = key.toLowerCase();
+
+        if (key === 'ctrl') {
+          key = 'Control';
+        } else if (key.length > 1) {
+          key = key.charAt(0).toUpperCase() + key.substr(1);
+        }
+
+        return key;
+      }
+    }
+  });
+}
+
+function insertMultiDragElements(clonesInserted, rootEl) {
+  multiDragElements.forEach(function (multiDragElement, i) {
+    var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
+
+    if (target) {
+      rootEl.insertBefore(multiDragElement, target);
+    } else {
+      rootEl.appendChild(multiDragElement);
+    }
+  });
+}
+/**
+ * Insert multi-drag clones
+ * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
+ * @param  {HTMLElement} rootEl
+ */
+
+
+function insertMultiDragClones(elementsInserted, rootEl) {
+  multiDragClones.forEach(function (clone, i) {
+    var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
+
+    if (target) {
+      rootEl.insertBefore(clone, target);
+    } else {
+      rootEl.appendChild(clone);
+    }
+  });
+}
+
+function removeMultiDragElements() {
+  multiDragElements.forEach(function (multiDragElement) {
+    if (multiDragElement === dragEl$1) return;
+    multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
+  });
+}
+
+Sortable.mount(new AutoScrollPlugin());
+Sortable.mount(Remove, Revert);
+
+Sortable.mount(new SwapPlugin());
+Sortable.mount(new MultiDragPlugin());
+
+export default Sortable;

+ 3698 - 0
public/assets/libs/Sortable/modular/sortable.core.esm.js

@@ -0,0 +1,3698 @@
+/**!
+ * Sortable 1.10.2
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @author	owenm    <owen23355@gmail.com>
+ * @license MIT
+ */
+function _typeof(obj) {
+  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+    _typeof = function (obj) {
+      return typeof obj;
+    };
+  } else {
+    _typeof = function (obj) {
+      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    };
+  }
+
+  return _typeof(obj);
+}
+
+function _defineProperty(obj, key, value) {
+  if (key in obj) {
+    Object.defineProperty(obj, key, {
+      value: value,
+      enumerable: true,
+      configurable: true,
+      writable: true
+    });
+  } else {
+    obj[key] = value;
+  }
+
+  return obj;
+}
+
+function _extends() {
+  _extends = Object.assign || function (target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i];
+
+      for (var key in source) {
+        if (Object.prototype.hasOwnProperty.call(source, key)) {
+          target[key] = source[key];
+        }
+      }
+    }
+
+    return target;
+  };
+
+  return _extends.apply(this, arguments);
+}
+
+function _objectSpread(target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i] != null ? arguments[i] : {};
+    var ownKeys = Object.keys(source);
+
+    if (typeof Object.getOwnPropertySymbols === 'function') {
+      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
+        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
+      }));
+    }
+
+    ownKeys.forEach(function (key) {
+      _defineProperty(target, key, source[key]);
+    });
+  }
+
+  return target;
+}
+
+function _objectWithoutPropertiesLoose(source, excluded) {
+  if (source == null) return {};
+  var target = {};
+  var sourceKeys = Object.keys(source);
+  var key, i;
+
+  for (i = 0; i < sourceKeys.length; i++) {
+    key = sourceKeys[i];
+    if (excluded.indexOf(key) >= 0) continue;
+    target[key] = source[key];
+  }
+
+  return target;
+}
+
+function _objectWithoutProperties(source, excluded) {
+  if (source == null) return {};
+
+  var target = _objectWithoutPropertiesLoose(source, excluded);
+
+  var key, i;
+
+  if (Object.getOwnPropertySymbols) {
+    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
+
+    for (i = 0; i < sourceSymbolKeys.length; i++) {
+      key = sourceSymbolKeys[i];
+      if (excluded.indexOf(key) >= 0) continue;
+      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
+      target[key] = source[key];
+    }
+  }
+
+  return target;
+}
+
+function _toConsumableArray(arr) {
+  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
+}
+
+function _arrayWithoutHoles(arr) {
+  if (Array.isArray(arr)) {
+    for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
+
+    return arr2;
+  }
+}
+
+function _iterableToArray(iter) {
+  if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
+}
+
+function _nonIterableSpread() {
+  throw new TypeError("Invalid attempt to spread non-iterable instance");
+}
+
+var version = "1.10.2";
+
+function userAgent(pattern) {
+  if (typeof window !== 'undefined' && window.navigator) {
+    return !!
+    /*@__PURE__*/
+    navigator.userAgent.match(pattern);
+  }
+}
+
+var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
+var Edge = userAgent(/Edge/i);
+var FireFox = userAgent(/firefox/i);
+var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
+var IOS = userAgent(/iP(ad|od|hone)/i);
+var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
+
+var captureMode = {
+  capture: false,
+  passive: false
+};
+
+function on(el, event, fn) {
+  el.addEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function off(el, event, fn) {
+  el.removeEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function matches(
+/**HTMLElement*/
+el,
+/**String*/
+selector) {
+  if (!selector) return;
+  selector[0] === '>' && (selector = selector.substring(1));
+
+  if (el) {
+    try {
+      if (el.matches) {
+        return el.matches(selector);
+      } else if (el.msMatchesSelector) {
+        return el.msMatchesSelector(selector);
+      } else if (el.webkitMatchesSelector) {
+        return el.webkitMatchesSelector(selector);
+      }
+    } catch (_) {
+      return false;
+    }
+  }
+
+  return false;
+}
+
+function getParentOrHost(el) {
+  return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
+}
+
+function closest(
+/**HTMLElement*/
+el,
+/**String*/
+selector,
+/**HTMLElement*/
+ctx, includeCTX) {
+  if (el) {
+    ctx = ctx || document;
+
+    do {
+      if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
+        return el;
+      }
+
+      if (el === ctx) break;
+      /* jshint boss:true */
+    } while (el = getParentOrHost(el));
+  }
+
+  return null;
+}
+
+var R_SPACE = /\s+/g;
+
+function toggleClass(el, name, state) {
+  if (el && name) {
+    if (el.classList) {
+      el.classList[state ? 'add' : 'remove'](name);
+    } else {
+      var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
+      el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
+    }
+  }
+}
+
+function css(el, prop, val) {
+  var style = el && el.style;
+
+  if (style) {
+    if (val === void 0) {
+      if (document.defaultView && document.defaultView.getComputedStyle) {
+        val = document.defaultView.getComputedStyle(el, '');
+      } else if (el.currentStyle) {
+        val = el.currentStyle;
+      }
+
+      return prop === void 0 ? val : val[prop];
+    } else {
+      if (!(prop in style) && prop.indexOf('webkit') === -1) {
+        prop = '-webkit-' + prop;
+      }
+
+      style[prop] = val + (typeof val === 'string' ? '' : 'px');
+    }
+  }
+}
+
+function matrix(el, selfOnly) {
+  var appliedTransforms = '';
+
+  if (typeof el === 'string') {
+    appliedTransforms = el;
+  } else {
+    do {
+      var transform = css(el, 'transform');
+
+      if (transform && transform !== 'none') {
+        appliedTransforms = transform + ' ' + appliedTransforms;
+      }
+      /* jshint boss:true */
+
+    } while (!selfOnly && (el = el.parentNode));
+  }
+
+  var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
+  /*jshint -W056 */
+
+  return matrixFn && new matrixFn(appliedTransforms);
+}
+
+function find(ctx, tagName, iterator) {
+  if (ctx) {
+    var list = ctx.getElementsByTagName(tagName),
+        i = 0,
+        n = list.length;
+
+    if (iterator) {
+      for (; i < n; i++) {
+        iterator(list[i], i);
+      }
+    }
+
+    return list;
+  }
+
+  return [];
+}
+
+function getWindowScrollingElement() {
+  var scrollingElement = document.scrollingElement;
+
+  if (scrollingElement) {
+    return scrollingElement;
+  } else {
+    return document.documentElement;
+  }
+}
+/**
+ * Returns the "bounding client rect" of given element
+ * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
+ * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
+ * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
+ * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
+ * @param  {[HTMLElement]} container              The parent the element will be placed in
+ * @return {Object}                               The boundingClientRect of el, with specified adjustments
+ */
+
+
+function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
+  if (!el.getBoundingClientRect && el !== window) return;
+  var elRect, top, left, bottom, right, height, width;
+
+  if (el !== window && el !== getWindowScrollingElement()) {
+    elRect = el.getBoundingClientRect();
+    top = elRect.top;
+    left = elRect.left;
+    bottom = elRect.bottom;
+    right = elRect.right;
+    height = elRect.height;
+    width = elRect.width;
+  } else {
+    top = 0;
+    left = 0;
+    bottom = window.innerHeight;
+    right = window.innerWidth;
+    height = window.innerHeight;
+    width = window.innerWidth;
+  }
+
+  if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
+    // Adjust for translate()
+    container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
+    // Not needed on <= IE11
+
+    if (!IE11OrLess) {
+      do {
+        if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
+          var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
+
+          top -= containerRect.top + parseInt(css(container, 'border-top-width'));
+          left -= containerRect.left + parseInt(css(container, 'border-left-width'));
+          bottom = top + elRect.height;
+          right = left + elRect.width;
+          break;
+        }
+        /* jshint boss:true */
+
+      } while (container = container.parentNode);
+    }
+  }
+
+  if (undoScale && el !== window) {
+    // Adjust for scale()
+    var elMatrix = matrix(container || el),
+        scaleX = elMatrix && elMatrix.a,
+        scaleY = elMatrix && elMatrix.d;
+
+    if (elMatrix) {
+      top /= scaleY;
+      left /= scaleX;
+      width /= scaleX;
+      height /= scaleY;
+      bottom = top + height;
+      right = left + width;
+    }
+  }
+
+  return {
+    top: top,
+    left: left,
+    bottom: bottom,
+    right: right,
+    width: width,
+    height: height
+  };
+}
+/**
+ * Checks if a side of an element is scrolled past a side of its parents
+ * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
+ * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
+ * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
+ * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
+ */
+
+
+function isScrolledPast(el, elSide, parentSide) {
+  var parent = getParentAutoScrollElement(el, true),
+      elSideVal = getRect(el)[elSide];
+  /* jshint boss:true */
+
+  while (parent) {
+    var parentSideVal = getRect(parent)[parentSide],
+        visible = void 0;
+
+    if (parentSide === 'top' || parentSide === 'left') {
+      visible = elSideVal >= parentSideVal;
+    } else {
+      visible = elSideVal <= parentSideVal;
+    }
+
+    if (!visible) return parent;
+    if (parent === getWindowScrollingElement()) break;
+    parent = getParentAutoScrollElement(parent, false);
+  }
+
+  return false;
+}
+/**
+ * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
+ * and non-draggable elements
+ * @param  {HTMLElement} el       The parent element
+ * @param  {Number} childNum      The index of the child
+ * @param  {Object} options       Parent Sortable's options
+ * @return {HTMLElement}          The child at index childNum, or null if not found
+ */
+
+
+function getChild(el, childNum, options) {
+  var currentChild = 0,
+      i = 0,
+      children = el.children;
+
+  while (i < children.length) {
+    if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && children[i] !== Sortable.dragged && closest(children[i], options.draggable, el, false)) {
+      if (currentChild === childNum) {
+        return children[i];
+      }
+
+      currentChild++;
+    }
+
+    i++;
+  }
+
+  return null;
+}
+/**
+ * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
+ * @param  {HTMLElement} el       Parent element
+ * @param  {selector} selector    Any other elements that should be ignored
+ * @return {HTMLElement}          The last child, ignoring ghostEl
+ */
+
+
+function lastChild(el, selector) {
+  var last = el.lastElementChild;
+
+  while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
+    last = last.previousElementSibling;
+  }
+
+  return last || null;
+}
+/**
+ * Returns the index of an element within its parent for a selected set of
+ * elements
+ * @param  {HTMLElement} el
+ * @param  {selector} selector
+ * @return {number}
+ */
+
+
+function index(el, selector) {
+  var index = 0;
+
+  if (!el || !el.parentNode) {
+    return -1;
+  }
+  /* jshint boss:true */
+
+
+  while (el = el.previousElementSibling) {
+    if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
+      index++;
+    }
+  }
+
+  return index;
+}
+/**
+ * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
+ * The value is returned in real pixels.
+ * @param  {HTMLElement} el
+ * @return {Array}             Offsets in the format of [left, top]
+ */
+
+
+function getRelativeScrollOffset(el) {
+  var offsetLeft = 0,
+      offsetTop = 0,
+      winScroller = getWindowScrollingElement();
+
+  if (el) {
+    do {
+      var elMatrix = matrix(el),
+          scaleX = elMatrix.a,
+          scaleY = elMatrix.d;
+      offsetLeft += el.scrollLeft * scaleX;
+      offsetTop += el.scrollTop * scaleY;
+    } while (el !== winScroller && (el = el.parentNode));
+  }
+
+  return [offsetLeft, offsetTop];
+}
+/**
+ * Returns the index of the object within the given array
+ * @param  {Array} arr   Array that may or may not hold the object
+ * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
+ * @return {Number}      The index of the object in the array, or -1
+ */
+
+
+function indexOfObject(arr, obj) {
+  for (var i in arr) {
+    if (!arr.hasOwnProperty(i)) continue;
+
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
+    }
+  }
+
+  return -1;
+}
+
+function getParentAutoScrollElement(el, includeSelf) {
+  // skip to window
+  if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
+  var elem = el;
+  var gotSelf = false;
+
+  do {
+    // we don't need to get elem css if it isn't even overflowing in the first place (performance)
+    if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
+      var elemCSS = css(elem);
+
+      if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
+        if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
+        if (gotSelf || includeSelf) return elem;
+        gotSelf = true;
+      }
+    }
+    /* jshint boss:true */
+
+  } while (elem = elem.parentNode);
+
+  return getWindowScrollingElement();
+}
+
+function extend(dst, src) {
+  if (dst && src) {
+    for (var key in src) {
+      if (src.hasOwnProperty(key)) {
+        dst[key] = src[key];
+      }
+    }
+  }
+
+  return dst;
+}
+
+function isRectEqual(rect1, rect2) {
+  return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
+}
+
+var _throttleTimeout;
+
+function throttle(callback, ms) {
+  return function () {
+    if (!_throttleTimeout) {
+      var args = arguments,
+          _this = this;
+
+      if (args.length === 1) {
+        callback.call(_this, args[0]);
+      } else {
+        callback.apply(_this, args);
+      }
+
+      _throttleTimeout = setTimeout(function () {
+        _throttleTimeout = void 0;
+      }, ms);
+    }
+  };
+}
+
+function cancelThrottle() {
+  clearTimeout(_throttleTimeout);
+  _throttleTimeout = void 0;
+}
+
+function scrollBy(el, x, y) {
+  el.scrollLeft += x;
+  el.scrollTop += y;
+}
+
+function clone(el) {
+  var Polymer = window.Polymer;
+  var $ = window.jQuery || window.Zepto;
+
+  if (Polymer && Polymer.dom) {
+    return Polymer.dom(el).cloneNode(true);
+  } else if ($) {
+    return $(el).clone(true)[0];
+  } else {
+    return el.cloneNode(true);
+  }
+}
+
+function setRect(el, rect) {
+  css(el, 'position', 'absolute');
+  css(el, 'top', rect.top);
+  css(el, 'left', rect.left);
+  css(el, 'width', rect.width);
+  css(el, 'height', rect.height);
+}
+
+function unsetRect(el) {
+  css(el, 'position', '');
+  css(el, 'top', '');
+  css(el, 'left', '');
+  css(el, 'width', '');
+  css(el, 'height', '');
+}
+
+var expando = 'Sortable' + new Date().getTime();
+
+function AnimationStateManager() {
+  var animationStates = [],
+      animationCallbackId;
+  return {
+    captureAnimationState: function captureAnimationState() {
+      animationStates = [];
+      if (!this.options.animation) return;
+      var children = [].slice.call(this.el.children);
+      children.forEach(function (child) {
+        if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
+        animationStates.push({
+          target: child,
+          rect: getRect(child)
+        });
+
+        var fromRect = _objectSpread({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation
+
+
+        if (child.thisAnimationDuration) {
+          var childMatrix = matrix(child, true);
+
+          if (childMatrix) {
+            fromRect.top -= childMatrix.f;
+            fromRect.left -= childMatrix.e;
+          }
+        }
+
+        child.fromRect = fromRect;
+      });
+    },
+    addAnimationState: function addAnimationState(state) {
+      animationStates.push(state);
+    },
+    removeAnimationState: function removeAnimationState(target) {
+      animationStates.splice(indexOfObject(animationStates, {
+        target: target
+      }), 1);
+    },
+    animateAll: function animateAll(callback) {
+      var _this = this;
+
+      if (!this.options.animation) {
+        clearTimeout(animationCallbackId);
+        if (typeof callback === 'function') callback();
+        return;
+      }
+
+      var animating = false,
+          animationTime = 0;
+      animationStates.forEach(function (state) {
+        var time = 0,
+            target = state.target,
+            fromRect = target.fromRect,
+            toRect = getRect(target),
+            prevFromRect = target.prevFromRect,
+            prevToRect = target.prevToRect,
+            animatingRect = state.rect,
+            targetMatrix = matrix(target, true);
+
+        if (targetMatrix) {
+          // Compensate for current animation
+          toRect.top -= targetMatrix.f;
+          toRect.left -= targetMatrix.e;
+        }
+
+        target.toRect = toRect;
+
+        if (target.thisAnimationDuration) {
+          // Could also check if animatingRect is between fromRect and toRect
+          if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
+          (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
+            // If returning to same place as started from animation and on same axis
+            time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
+          }
+        } // if fromRect != toRect: animate
+
+
+        if (!isRectEqual(toRect, fromRect)) {
+          target.prevFromRect = fromRect;
+          target.prevToRect = toRect;
+
+          if (!time) {
+            time = _this.options.animation;
+          }
+
+          _this.animate(target, animatingRect, toRect, time);
+        }
+
+        if (time) {
+          animating = true;
+          animationTime = Math.max(animationTime, time);
+          clearTimeout(target.animationResetTimer);
+          target.animationResetTimer = setTimeout(function () {
+            target.animationTime = 0;
+            target.prevFromRect = null;
+            target.fromRect = null;
+            target.prevToRect = null;
+            target.thisAnimationDuration = null;
+          }, time);
+          target.thisAnimationDuration = time;
+        }
+      });
+      clearTimeout(animationCallbackId);
+
+      if (!animating) {
+        if (typeof callback === 'function') callback();
+      } else {
+        animationCallbackId = setTimeout(function () {
+          if (typeof callback === 'function') callback();
+        }, animationTime);
+      }
+
+      animationStates = [];
+    },
+    animate: function animate(target, currentRect, toRect, duration) {
+      if (duration) {
+        css(target, 'transition', '');
+        css(target, 'transform', '');
+        var elMatrix = matrix(this.el),
+            scaleX = elMatrix && elMatrix.a,
+            scaleY = elMatrix && elMatrix.d,
+            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
+            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
+        target.animatingX = !!translateX;
+        target.animatingY = !!translateY;
+        css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
+        repaint(target); // repaint
+
+        css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
+        css(target, 'transform', 'translate3d(0,0,0)');
+        typeof target.animated === 'number' && clearTimeout(target.animated);
+        target.animated = setTimeout(function () {
+          css(target, 'transition', '');
+          css(target, 'transform', '');
+          target.animated = false;
+          target.animatingX = false;
+          target.animatingY = false;
+        }, duration);
+      }
+    }
+  };
+}
+
+function repaint(target) {
+  return target.offsetWidth;
+}
+
+function calculateRealTime(animatingRect, fromRect, toRect, options) {
+  return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
+}
+
+var plugins = [];
+var defaults = {
+  initializeByDefault: true
+};
+var PluginManager = {
+  mount: function mount(plugin) {
+    // Set default static properties
+    for (var option in defaults) {
+      if (defaults.hasOwnProperty(option) && !(option in plugin)) {
+        plugin[option] = defaults[option];
+      }
+    }
+
+    plugins.push(plugin);
+  },
+  pluginEvent: function pluginEvent(eventName, sortable, evt) {
+    var _this = this;
+
+    this.eventCanceled = false;
+
+    evt.cancel = function () {
+      _this.eventCanceled = true;
+    };
+
+    var eventNameGlobal = eventName + 'Global';
+    plugins.forEach(function (plugin) {
+      if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
+
+      if (sortable[plugin.pluginName][eventNameGlobal]) {
+        sortable[plugin.pluginName][eventNameGlobal](_objectSpread({
+          sortable: sortable
+        }, evt));
+      } // Only fire plugin event if plugin is enabled in this sortable,
+      // and plugin has event defined
+
+
+      if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
+        sortable[plugin.pluginName][eventName](_objectSpread({
+          sortable: sortable
+        }, evt));
+      }
+    });
+  },
+  initializePlugins: function initializePlugins(sortable, el, defaults, options) {
+    plugins.forEach(function (plugin) {
+      var pluginName = plugin.pluginName;
+      if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
+      var initialized = new plugin(sortable, el, sortable.options);
+      initialized.sortable = sortable;
+      initialized.options = sortable.options;
+      sortable[pluginName] = initialized; // Add default options from plugin
+
+      _extends(defaults, initialized.defaults);
+    });
+
+    for (var option in sortable.options) {
+      if (!sortable.options.hasOwnProperty(option)) continue;
+      var modified = this.modifyOption(sortable, option, sortable.options[option]);
+
+      if (typeof modified !== 'undefined') {
+        sortable.options[option] = modified;
+      }
+    }
+  },
+  getEventProperties: function getEventProperties(name, sortable) {
+    var eventProperties = {};
+    plugins.forEach(function (plugin) {
+      if (typeof plugin.eventProperties !== 'function') return;
+
+      _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
+    });
+    return eventProperties;
+  },
+  modifyOption: function modifyOption(sortable, name, value) {
+    var modifiedValue;
+    plugins.forEach(function (plugin) {
+      // Plugin must exist on the Sortable
+      if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
+
+      if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
+        modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
+      }
+    });
+    return modifiedValue;
+  }
+};
+
+function dispatchEvent(_ref) {
+  var sortable = _ref.sortable,
+      rootEl = _ref.rootEl,
+      name = _ref.name,
+      targetEl = _ref.targetEl,
+      cloneEl = _ref.cloneEl,
+      toEl = _ref.toEl,
+      fromEl = _ref.fromEl,
+      oldIndex = _ref.oldIndex,
+      newIndex = _ref.newIndex,
+      oldDraggableIndex = _ref.oldDraggableIndex,
+      newDraggableIndex = _ref.newDraggableIndex,
+      originalEvent = _ref.originalEvent,
+      putSortable = _ref.putSortable,
+      extraEventProperties = _ref.extraEventProperties;
+  sortable = sortable || rootEl && rootEl[expando];
+  if (!sortable) return;
+  var evt,
+      options = sortable.options,
+      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
+
+  if (window.CustomEvent && !IE11OrLess && !Edge) {
+    evt = new CustomEvent(name, {
+      bubbles: true,
+      cancelable: true
+    });
+  } else {
+    evt = document.createEvent('Event');
+    evt.initEvent(name, true, true);
+  }
+
+  evt.to = toEl || rootEl;
+  evt.from = fromEl || rootEl;
+  evt.item = targetEl || rootEl;
+  evt.clone = cloneEl;
+  evt.oldIndex = oldIndex;
+  evt.newIndex = newIndex;
+  evt.oldDraggableIndex = oldDraggableIndex;
+  evt.newDraggableIndex = newDraggableIndex;
+  evt.originalEvent = originalEvent;
+  evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
+
+  var allEventProperties = _objectSpread({}, extraEventProperties, PluginManager.getEventProperties(name, sortable));
+
+  for (var option in allEventProperties) {
+    evt[option] = allEventProperties[option];
+  }
+
+  if (rootEl) {
+    rootEl.dispatchEvent(evt);
+  }
+
+  if (options[onName]) {
+    options[onName].call(sortable, evt);
+  }
+}
+
+var pluginEvent = function pluginEvent(eventName, sortable) {
+  var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
+      originalEvent = _ref.evt,
+      data = _objectWithoutProperties(_ref, ["evt"]);
+
+  PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread({
+    dragEl: dragEl,
+    parentEl: parentEl,
+    ghostEl: ghostEl,
+    rootEl: rootEl,
+    nextEl: nextEl,
+    lastDownEl: lastDownEl,
+    cloneEl: cloneEl,
+    cloneHidden: cloneHidden,
+    dragStarted: moved,
+    putSortable: putSortable,
+    activeSortable: Sortable.active,
+    originalEvent: originalEvent,
+    oldIndex: oldIndex,
+    oldDraggableIndex: oldDraggableIndex,
+    newIndex: newIndex,
+    newDraggableIndex: newDraggableIndex,
+    hideGhostForTarget: _hideGhostForTarget,
+    unhideGhostForTarget: _unhideGhostForTarget,
+    cloneNowHidden: function cloneNowHidden() {
+      cloneHidden = true;
+    },
+    cloneNowShown: function cloneNowShown() {
+      cloneHidden = false;
+    },
+    dispatchSortableEvent: function dispatchSortableEvent(name) {
+      _dispatchEvent({
+        sortable: sortable,
+        name: name,
+        originalEvent: originalEvent
+      });
+    }
+  }, data));
+};
+
+function _dispatchEvent(info) {
+  dispatchEvent(_objectSpread({
+    putSortable: putSortable,
+    cloneEl: cloneEl,
+    targetEl: dragEl,
+    rootEl: rootEl,
+    oldIndex: oldIndex,
+    oldDraggableIndex: oldDraggableIndex,
+    newIndex: newIndex,
+    newDraggableIndex: newDraggableIndex
+  }, info));
+}
+
+var dragEl,
+    parentEl,
+    ghostEl,
+    rootEl,
+    nextEl,
+    lastDownEl,
+    cloneEl,
+    cloneHidden,
+    oldIndex,
+    newIndex,
+    oldDraggableIndex,
+    newDraggableIndex,
+    activeGroup,
+    putSortable,
+    awaitingDragStarted = false,
+    ignoreNextClick = false,
+    sortables = [],
+    tapEvt,
+    touchEvt,
+    lastDx,
+    lastDy,
+    tapDistanceLeft,
+    tapDistanceTop,
+    moved,
+    lastTarget,
+    lastDirection,
+    pastFirstInvertThresh = false,
+    isCircumstantialInvert = false,
+    targetMoveDistance,
+    // For positioning ghost absolutely
+ghostRelativeParent,
+    ghostRelativeParentInitialScroll = [],
+    // (left, top)
+_silent = false,
+    savedInputChecked = [];
+/** @const */
+
+var documentExists = typeof document !== 'undefined',
+    PositionGhostAbsolutely = IOS,
+    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
+    // This will not pass for IE9, because IE9 DnD only works on anchors
+supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
+    supportCssPointerEvents = function () {
+  if (!documentExists) return; // false when <= IE11
+
+  if (IE11OrLess) {
+    return false;
+  }
+
+  var el = document.createElement('x');
+  el.style.cssText = 'pointer-events:auto';
+  return el.style.pointerEvents === 'auto';
+}(),
+    _detectDirection = function _detectDirection(el, options) {
+  var elCSS = css(el),
+      elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
+      child1 = getChild(el, 0, options),
+      child2 = getChild(el, 1, options),
+      firstChildCSS = child1 && css(child1),
+      secondChildCSS = child2 && css(child2),
+      firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
+      secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
+
+  if (elCSS.display === 'flex') {
+    return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
+  }
+
+  if (elCSS.display === 'grid') {
+    return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
+  }
+
+  if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
+    var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
+    return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
+  }
+
+  return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
+},
+    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
+  var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
+      dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
+      dragElOppLength = vertical ? dragRect.width : dragRect.height,
+      targetS1Opp = vertical ? targetRect.left : targetRect.top,
+      targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
+      targetOppLength = vertical ? targetRect.width : targetRect.height;
+  return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
+},
+
+/**
+ * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
+ * @param  {Number} x      X position
+ * @param  {Number} y      Y position
+ * @return {HTMLElement}   Element of the first found nearest Sortable
+ */
+_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
+  var ret;
+  sortables.some(function (sortable) {
+    if (lastChild(sortable)) return;
+    var rect = getRect(sortable),
+        threshold = sortable[expando].options.emptyInsertThreshold,
+        insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
+        insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
+
+    if (threshold && insideHorizontally && insideVertically) {
+      return ret = sortable;
+    }
+  });
+  return ret;
+},
+    _prepareGroup = function _prepareGroup(options) {
+  function toFn(value, pull) {
+    return function (to, from, dragEl, evt) {
+      var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
+
+      if (value == null && (pull || sameGroup)) {
+        // Default pull value
+        // Default pull and put value if same group
+        return true;
+      } else if (value == null || value === false) {
+        return false;
+      } else if (pull && value === 'clone') {
+        return value;
+      } else if (typeof value === 'function') {
+        return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
+      } else {
+        var otherGroup = (pull ? to : from).options.group.name;
+        return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
+      }
+    };
+  }
+
+  var group = {};
+  var originalGroup = options.group;
+
+  if (!originalGroup || _typeof(originalGroup) != 'object') {
+    originalGroup = {
+      name: originalGroup
+    };
+  }
+
+  group.name = originalGroup.name;
+  group.checkPull = toFn(originalGroup.pull, true);
+  group.checkPut = toFn(originalGroup.put);
+  group.revertClone = originalGroup.revertClone;
+  options.group = group;
+},
+    _hideGhostForTarget = function _hideGhostForTarget() {
+  if (!supportCssPointerEvents && ghostEl) {
+    css(ghostEl, 'display', 'none');
+  }
+},
+    _unhideGhostForTarget = function _unhideGhostForTarget() {
+  if (!supportCssPointerEvents && ghostEl) {
+    css(ghostEl, 'display', '');
+  }
+}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
+
+
+if (documentExists) {
+  document.addEventListener('click', function (evt) {
+    if (ignoreNextClick) {
+      evt.preventDefault();
+      evt.stopPropagation && evt.stopPropagation();
+      evt.stopImmediatePropagation && evt.stopImmediatePropagation();
+      ignoreNextClick = false;
+      return false;
+    }
+  }, true);
+}
+
+var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
+  if (dragEl) {
+    evt = evt.touches ? evt.touches[0] : evt;
+
+    var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
+
+    if (nearest) {
+      // Create imitation event
+      var event = {};
+
+      for (var i in evt) {
+        if (evt.hasOwnProperty(i)) {
+          event[i] = evt[i];
+        }
+      }
+
+      event.target = event.rootEl = nearest;
+      event.preventDefault = void 0;
+      event.stopPropagation = void 0;
+
+      nearest[expando]._onDragOver(event);
+    }
+  }
+};
+
+var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
+  if (dragEl) {
+    dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
+  }
+};
+/**
+ * @class  Sortable
+ * @param  {HTMLElement}  el
+ * @param  {Object}       [options]
+ */
+
+
+function Sortable(el, options) {
+  if (!(el && el.nodeType && el.nodeType === 1)) {
+    throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
+  }
+
+  this.el = el; // root element
+
+  this.options = options = _extends({}, options); // Export instance
+
+  el[expando] = this;
+  var defaults = {
+    group: null,
+    sort: true,
+    disabled: false,
+    store: null,
+    handle: null,
+    draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
+    swapThreshold: 1,
+    // percentage; 0 <= x <= 1
+    invertSwap: false,
+    // invert always
+    invertedSwapThreshold: null,
+    // will be set to same as swapThreshold if default
+    removeCloneOnHide: true,
+    direction: function direction() {
+      return _detectDirection(el, this.options);
+    },
+    ghostClass: 'sortable-ghost',
+    chosenClass: 'sortable-chosen',
+    dragClass: 'sortable-drag',
+    ignore: 'a, img',
+    filter: null,
+    preventOnFilter: true,
+    animation: 0,
+    easing: null,
+    setData: function setData(dataTransfer, dragEl) {
+      dataTransfer.setData('Text', dragEl.textContent);
+    },
+    dropBubble: false,
+    dragoverBubble: false,
+    dataIdAttr: 'data-id',
+    delay: 0,
+    delayOnTouchOnly: false,
+    touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
+    forceFallback: false,
+    fallbackClass: 'sortable-fallback',
+    fallbackOnBody: false,
+    fallbackTolerance: 0,
+    fallbackOffset: {
+      x: 0,
+      y: 0
+    },
+    supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window,
+    emptyInsertThreshold: 5
+  };
+  PluginManager.initializePlugins(this, el, defaults); // Set default options
+
+  for (var name in defaults) {
+    !(name in options) && (options[name] = defaults[name]);
+  }
+
+  _prepareGroup(options); // Bind all private methods
+
+
+  for (var fn in this) {
+    if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+      this[fn] = this[fn].bind(this);
+    }
+  } // Setup drag mode
+
+
+  this.nativeDraggable = options.forceFallback ? false : supportDraggable;
+
+  if (this.nativeDraggable) {
+    // Touch start threshold cannot be greater than the native dragstart threshold
+    this.options.touchStartThreshold = 1;
+  } // Bind events
+
+
+  if (options.supportPointer) {
+    on(el, 'pointerdown', this._onTapStart);
+  } else {
+    on(el, 'mousedown', this._onTapStart);
+    on(el, 'touchstart', this._onTapStart);
+  }
+
+  if (this.nativeDraggable) {
+    on(el, 'dragover', this);
+    on(el, 'dragenter', this);
+  }
+
+  sortables.push(this.el); // Restore sorting
+
+  options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
+
+  _extends(this, AnimationStateManager());
+}
+
+Sortable.prototype =
+/** @lends Sortable.prototype */
+{
+  constructor: Sortable,
+  _isOutsideThisEl: function _isOutsideThisEl(target) {
+    if (!this.el.contains(target) && target !== this.el) {
+      lastTarget = null;
+    }
+  },
+  _getDirection: function _getDirection(evt, target) {
+    return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
+  },
+  _onTapStart: function _onTapStart(
+  /** Event|TouchEvent */
+  evt) {
+    if (!evt.cancelable) return;
+
+    var _this = this,
+        el = this.el,
+        options = this.options,
+        preventOnFilter = options.preventOnFilter,
+        type = evt.type,
+        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
+        target = (touch || evt).target,
+        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
+        filter = options.filter;
+
+    _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
+
+
+    if (dragEl) {
+      return;
+    }
+
+    if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
+      return; // only left button and enabled
+    } // cancel dnd if original target is content editable
+
+
+    if (originalTarget.isContentEditable) {
+      return;
+    }
+
+    target = closest(target, options.draggable, el, false);
+
+    if (target && target.animated) {
+      return;
+    }
+
+    if (lastDownEl === target) {
+      // Ignoring duplicate `down`
+      return;
+    } // Get the index of the dragged element within its parent
+
+
+    oldIndex = index(target);
+    oldDraggableIndex = index(target, options.draggable); // Check filter
+
+    if (typeof filter === 'function') {
+      if (filter.call(this, evt, target, this)) {
+        _dispatchEvent({
+          sortable: _this,
+          rootEl: originalTarget,
+          name: 'filter',
+          targetEl: target,
+          toEl: el,
+          fromEl: el
+        });
+
+        pluginEvent('filter', _this, {
+          evt: evt
+        });
+        preventOnFilter && evt.cancelable && evt.preventDefault();
+        return; // cancel dnd
+      }
+    } else if (filter) {
+      filter = filter.split(',').some(function (criteria) {
+        criteria = closest(originalTarget, criteria.trim(), el, false);
+
+        if (criteria) {
+          _dispatchEvent({
+            sortable: _this,
+            rootEl: criteria,
+            name: 'filter',
+            targetEl: target,
+            fromEl: el,
+            toEl: el
+          });
+
+          pluginEvent('filter', _this, {
+            evt: evt
+          });
+          return true;
+        }
+      });
+
+      if (filter) {
+        preventOnFilter && evt.cancelable && evt.preventDefault();
+        return; // cancel dnd
+      }
+    }
+
+    if (options.handle && !closest(originalTarget, options.handle, el, false)) {
+      return;
+    } // Prepare `dragstart`
+
+
+    this._prepareDragStart(evt, touch, target);
+  },
+  _prepareDragStart: function _prepareDragStart(
+  /** Event */
+  evt,
+  /** Touch */
+  touch,
+  /** HTMLElement */
+  target) {
+    var _this = this,
+        el = _this.el,
+        options = _this.options,
+        ownerDocument = el.ownerDocument,
+        dragStartFn;
+
+    if (target && !dragEl && target.parentNode === el) {
+      var dragRect = getRect(target);
+      rootEl = el;
+      dragEl = target;
+      parentEl = dragEl.parentNode;
+      nextEl = dragEl.nextSibling;
+      lastDownEl = target;
+      activeGroup = options.group;
+      Sortable.dragged = dragEl;
+      tapEvt = {
+        target: dragEl,
+        clientX: (touch || evt).clientX,
+        clientY: (touch || evt).clientY
+      };
+      tapDistanceLeft = tapEvt.clientX - dragRect.left;
+      tapDistanceTop = tapEvt.clientY - dragRect.top;
+      this._lastX = (touch || evt).clientX;
+      this._lastY = (touch || evt).clientY;
+      dragEl.style['will-change'] = 'all';
+
+      dragStartFn = function dragStartFn() {
+        pluginEvent('delayEnded', _this, {
+          evt: evt
+        });
+
+        if (Sortable.eventCanceled) {
+          _this._onDrop();
+
+          return;
+        } // Delayed drag has been triggered
+        // we can re-enable the events: touchmove/mousemove
+
+
+        _this._disableDelayedDragEvents();
+
+        if (!FireFox && _this.nativeDraggable) {
+          dragEl.draggable = true;
+        } // Bind the events: dragstart/dragend
+
+
+        _this._triggerDragStart(evt, touch); // Drag start event
+
+
+        _dispatchEvent({
+          sortable: _this,
+          name: 'choose',
+          originalEvent: evt
+        }); // Chosen item
+
+
+        toggleClass(dragEl, options.chosenClass, true);
+      }; // Disable "draggable"
+
+
+      options.ignore.split(',').forEach(function (criteria) {
+        find(dragEl, criteria.trim(), _disableDraggable);
+      });
+      on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'mouseup', _this._onDrop);
+      on(ownerDocument, 'touchend', _this._onDrop);
+      on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
+
+      if (FireFox && this.nativeDraggable) {
+        this.options.touchStartThreshold = 4;
+        dragEl.draggable = true;
+      }
+
+      pluginEvent('delayStart', this, {
+        evt: evt
+      }); // Delay is impossible for native DnD in Edge or IE
+
+      if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
+        if (Sortable.eventCanceled) {
+          this._onDrop();
+
+          return;
+        } // If the user moves the pointer or let go the click or touch
+        // before the delay has been reached:
+        // disable the delayed drag
+
+
+        on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
+        on(ownerDocument, 'touchend', _this._disableDelayedDrag);
+        on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
+        on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
+        on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
+        options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
+        _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
+      } else {
+        dragStartFn();
+      }
+    }
+  },
+  _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
+  /** TouchEvent|PointerEvent **/
+  e) {
+    var touch = e.touches ? e.touches[0] : e;
+
+    if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
+      this._disableDelayedDrag();
+    }
+  },
+  _disableDelayedDrag: function _disableDelayedDrag() {
+    dragEl && _disableDraggable(dragEl);
+    clearTimeout(this._dragStartTimer);
+
+    this._disableDelayedDragEvents();
+  },
+  _disableDelayedDragEvents: function _disableDelayedDragEvents() {
+    var ownerDocument = this.el.ownerDocument;
+    off(ownerDocument, 'mouseup', this._disableDelayedDrag);
+    off(ownerDocument, 'touchend', this._disableDelayedDrag);
+    off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
+    off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
+    off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
+    off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
+  },
+  _triggerDragStart: function _triggerDragStart(
+  /** Event */
+  evt,
+  /** Touch */
+  touch) {
+    touch = touch || evt.pointerType == 'touch' && evt;
+
+    if (!this.nativeDraggable || touch) {
+      if (this.options.supportPointer) {
+        on(document, 'pointermove', this._onTouchMove);
+      } else if (touch) {
+        on(document, 'touchmove', this._onTouchMove);
+      } else {
+        on(document, 'mousemove', this._onTouchMove);
+      }
+    } else {
+      on(dragEl, 'dragend', this);
+      on(rootEl, 'dragstart', this._onDragStart);
+    }
+
+    try {
+      if (document.selection) {
+        // Timeout neccessary for IE9
+        _nextTick(function () {
+          document.selection.empty();
+        });
+      } else {
+        window.getSelection().removeAllRanges();
+      }
+    } catch (err) {}
+  },
+  _dragStarted: function _dragStarted(fallback, evt) {
+
+    awaitingDragStarted = false;
+
+    if (rootEl && dragEl) {
+      pluginEvent('dragStarted', this, {
+        evt: evt
+      });
+
+      if (this.nativeDraggable) {
+        on(document, 'dragover', _checkOutsideTargetEl);
+      }
+
+      var options = this.options; // Apply effect
+
+      !fallback && toggleClass(dragEl, options.dragClass, false);
+      toggleClass(dragEl, options.ghostClass, true);
+      Sortable.active = this;
+      fallback && this._appendGhost(); // Drag start event
+
+      _dispatchEvent({
+        sortable: this,
+        name: 'start',
+        originalEvent: evt
+      });
+    } else {
+      this._nulling();
+    }
+  },
+  _emulateDragOver: function _emulateDragOver() {
+    if (touchEvt) {
+      this._lastX = touchEvt.clientX;
+      this._lastY = touchEvt.clientY;
+
+      _hideGhostForTarget();
+
+      var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+      var parent = target;
+
+      while (target && target.shadowRoot) {
+        target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+        if (target === parent) break;
+        parent = target;
+      }
+
+      dragEl.parentNode[expando]._isOutsideThisEl(target);
+
+      if (parent) {
+        do {
+          if (parent[expando]) {
+            var inserted = void 0;
+            inserted = parent[expando]._onDragOver({
+              clientX: touchEvt.clientX,
+              clientY: touchEvt.clientY,
+              target: target,
+              rootEl: parent
+            });
+
+            if (inserted && !this.options.dragoverBubble) {
+              break;
+            }
+          }
+
+          target = parent; // store last element
+        }
+        /* jshint boss:true */
+        while (parent = parent.parentNode);
+      }
+
+      _unhideGhostForTarget();
+    }
+  },
+  _onTouchMove: function _onTouchMove(
+  /**TouchEvent*/
+  evt) {
+    if (tapEvt) {
+      var options = this.options,
+          fallbackTolerance = options.fallbackTolerance,
+          fallbackOffset = options.fallbackOffset,
+          touch = evt.touches ? evt.touches[0] : evt,
+          ghostMatrix = ghostEl && matrix(ghostEl, true),
+          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
+          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
+          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
+          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
+          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging
+
+      if (!Sortable.active && !awaitingDragStarted) {
+        if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
+          return;
+        }
+
+        this._onDragStart(evt, true);
+      }
+
+      if (ghostEl) {
+        if (ghostMatrix) {
+          ghostMatrix.e += dx - (lastDx || 0);
+          ghostMatrix.f += dy - (lastDy || 0);
+        } else {
+          ghostMatrix = {
+            a: 1,
+            b: 0,
+            c: 0,
+            d: 1,
+            e: dx,
+            f: dy
+          };
+        }
+
+        var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
+        css(ghostEl, 'webkitTransform', cssMatrix);
+        css(ghostEl, 'mozTransform', cssMatrix);
+        css(ghostEl, 'msTransform', cssMatrix);
+        css(ghostEl, 'transform', cssMatrix);
+        lastDx = dx;
+        lastDy = dy;
+        touchEvt = touch;
+      }
+
+      evt.cancelable && evt.preventDefault();
+    }
+  },
+  _appendGhost: function _appendGhost() {
+    // Bug if using scale(): https://stackoverflow.com/questions/2637058
+    // Not being adjusted for
+    if (!ghostEl) {
+      var container = this.options.fallbackOnBody ? document.body : rootEl,
+          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
+          options = this.options; // Position absolutely
+
+      if (PositionGhostAbsolutely) {
+        // Get relatively positioned parent
+        ghostRelativeParent = container;
+
+        while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
+          ghostRelativeParent = ghostRelativeParent.parentNode;
+        }
+
+        if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
+          if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
+          rect.top += ghostRelativeParent.scrollTop;
+          rect.left += ghostRelativeParent.scrollLeft;
+        } else {
+          ghostRelativeParent = getWindowScrollingElement();
+        }
+
+        ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
+      }
+
+      ghostEl = dragEl.cloneNode(true);
+      toggleClass(ghostEl, options.ghostClass, false);
+      toggleClass(ghostEl, options.fallbackClass, true);
+      toggleClass(ghostEl, options.dragClass, true);
+      css(ghostEl, 'transition', '');
+      css(ghostEl, 'transform', '');
+      css(ghostEl, 'box-sizing', 'border-box');
+      css(ghostEl, 'margin', 0);
+      css(ghostEl, 'top', rect.top);
+      css(ghostEl, 'left', rect.left);
+      css(ghostEl, 'width', rect.width);
+      css(ghostEl, 'height', rect.height);
+      css(ghostEl, 'opacity', '0.8');
+      css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
+      css(ghostEl, 'zIndex', '100000');
+      css(ghostEl, 'pointerEvents', 'none');
+      Sortable.ghost = ghostEl;
+      container.appendChild(ghostEl); // Set transform-origin
+
+      css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
+    }
+  },
+  _onDragStart: function _onDragStart(
+  /**Event*/
+  evt,
+  /**boolean*/
+  fallback) {
+    var _this = this;
+
+    var dataTransfer = evt.dataTransfer;
+    var options = _this.options;
+    pluginEvent('dragStart', this, {
+      evt: evt
+    });
+
+    if (Sortable.eventCanceled) {
+      this._onDrop();
+
+      return;
+    }
+
+    pluginEvent('setupClone', this);
+
+    if (!Sortable.eventCanceled) {
+      cloneEl = clone(dragEl);
+      cloneEl.draggable = false;
+      cloneEl.style['will-change'] = '';
+
+      this._hideClone();
+
+      toggleClass(cloneEl, this.options.chosenClass, false);
+      Sortable.clone = cloneEl;
+    } // #1143: IFrame support workaround
+
+
+    _this.cloneId = _nextTick(function () {
+      pluginEvent('clone', _this);
+      if (Sortable.eventCanceled) return;
+
+      if (!_this.options.removeCloneOnHide) {
+        rootEl.insertBefore(cloneEl, dragEl);
+      }
+
+      _this._hideClone();
+
+      _dispatchEvent({
+        sortable: _this,
+        name: 'clone'
+      });
+    });
+    !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
+
+    if (fallback) {
+      ignoreNextClick = true;
+      _this._loopId = setInterval(_this._emulateDragOver, 50);
+    } else {
+      // Undo what was set in _prepareDragStart before drag started
+      off(document, 'mouseup', _this._onDrop);
+      off(document, 'touchend', _this._onDrop);
+      off(document, 'touchcancel', _this._onDrop);
+
+      if (dataTransfer) {
+        dataTransfer.effectAllowed = 'move';
+        options.setData && options.setData.call(_this, dataTransfer, dragEl);
+      }
+
+      on(document, 'drop', _this); // #1276 fix:
+
+      css(dragEl, 'transform', 'translateZ(0)');
+    }
+
+    awaitingDragStarted = true;
+    _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
+    on(document, 'selectstart', _this);
+    moved = true;
+
+    if (Safari) {
+      css(document.body, 'user-select', 'none');
+    }
+  },
+  // Returns true - if no further action is needed (either inserted or another condition)
+  _onDragOver: function _onDragOver(
+  /**Event*/
+  evt) {
+    var el = this.el,
+        target = evt.target,
+        dragRect,
+        targetRect,
+        revert,
+        options = this.options,
+        group = options.group,
+        activeSortable = Sortable.active,
+        isOwner = activeGroup === group,
+        canSort = options.sort,
+        fromSortable = putSortable || activeSortable,
+        vertical,
+        _this = this,
+        completedFired = false;
+
+    if (_silent) return;
+
+    function dragOverEvent(name, extra) {
+      pluginEvent(name, _this, _objectSpread({
+        evt: evt,
+        isOwner: isOwner,
+        axis: vertical ? 'vertical' : 'horizontal',
+        revert: revert,
+        dragRect: dragRect,
+        targetRect: targetRect,
+        canSort: canSort,
+        fromSortable: fromSortable,
+        target: target,
+        completed: completed,
+        onMove: function onMove(target, after) {
+          return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
+        },
+        changed: changed
+      }, extra));
+    } // Capture animation state
+
+
+    function capture() {
+      dragOverEvent('dragOverAnimationCapture');
+
+      _this.captureAnimationState();
+
+      if (_this !== fromSortable) {
+        fromSortable.captureAnimationState();
+      }
+    } // Return invocation when dragEl is inserted (or completed)
+
+
+    function completed(insertion) {
+      dragOverEvent('dragOverCompleted', {
+        insertion: insertion
+      });
+
+      if (insertion) {
+        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+        if (isOwner) {
+          activeSortable._hideClone();
+        } else {
+          activeSortable._showClone(_this);
+        }
+
+        if (_this !== fromSortable) {
+          // Set ghost class to new sortable's ghost class
+          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
+          toggleClass(dragEl, options.ghostClass, true);
+        }
+
+        if (putSortable !== _this && _this !== Sortable.active) {
+          putSortable = _this;
+        } else if (_this === Sortable.active && putSortable) {
+          putSortable = null;
+        } // Animation
+
+
+        if (fromSortable === _this) {
+          _this._ignoreWhileAnimating = target;
+        }
+
+        _this.animateAll(function () {
+          dragOverEvent('dragOverAnimationComplete');
+          _this._ignoreWhileAnimating = null;
+        });
+
+        if (_this !== fromSortable) {
+          fromSortable.animateAll();
+          fromSortable._ignoreWhileAnimating = null;
+        }
+      } // Null lastTarget if it is not inside a previously swapped element
+
+
+      if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
+        lastTarget = null;
+      } // no bubbling and not fallback
+
+
+      if (!options.dragoverBubble && !evt.rootEl && target !== document) {
+        dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
+
+
+        !insertion && nearestEmptyInsertDetectEvent(evt);
+      }
+
+      !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
+      return completedFired = true;
+    } // Call when dragEl has been inserted
+
+
+    function changed() {
+      newIndex = index(dragEl);
+      newDraggableIndex = index(dragEl, options.draggable);
+
+      _dispatchEvent({
+        sortable: _this,
+        name: 'change',
+        toEl: el,
+        newIndex: newIndex,
+        newDraggableIndex: newDraggableIndex,
+        originalEvent: evt
+      });
+    }
+
+    if (evt.preventDefault !== void 0) {
+      evt.cancelable && evt.preventDefault();
+    }
+
+    target = closest(target, options.draggable, el, true);
+    dragOverEvent('dragOver');
+    if (Sortable.eventCanceled) return completedFired;
+
+    if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
+      return completed(false);
+    }
+
+    ignoreNextClick = false;
+
+    if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
+    : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
+      vertical = this._getDirection(evt, target) === 'vertical';
+      dragRect = getRect(dragEl);
+      dragOverEvent('dragOverValid');
+      if (Sortable.eventCanceled) return completedFired;
+
+      if (revert) {
+        parentEl = rootEl; // actualization
+
+        capture();
+
+        this._hideClone();
+
+        dragOverEvent('revert');
+
+        if (!Sortable.eventCanceled) {
+          if (nextEl) {
+            rootEl.insertBefore(dragEl, nextEl);
+          } else {
+            rootEl.appendChild(dragEl);
+          }
+        }
+
+        return completed(true);
+      }
+
+      var elLastChild = lastChild(el, options.draggable);
+
+      if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
+        // If already at end of list: Do not insert
+        if (elLastChild === dragEl) {
+          return completed(false);
+        } // assign target only if condition is true
+
+
+        if (elLastChild && el === evt.target) {
+          target = elLastChild;
+        }
+
+        if (target) {
+          targetRect = getRect(target);
+        }
+
+        if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
+          capture();
+          el.appendChild(dragEl);
+          parentEl = el; // actualization
+
+          changed();
+          return completed(true);
+        }
+      } else if (target.parentNode === el) {
+        targetRect = getRect(target);
+        var direction = 0,
+            targetBeforeFirstSwap,
+            differentLevel = dragEl.parentNode !== el,
+            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
+            side1 = vertical ? 'top' : 'left',
+            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
+            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
+
+        if (lastTarget !== target) {
+          targetBeforeFirstSwap = targetRect[side1];
+          pastFirstInvertThresh = false;
+          isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
+        }
+
+        direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
+        var sibling;
+
+        if (direction !== 0) {
+          // Check if target is beside dragEl in respective direction (ignoring hidden elements)
+          var dragIndex = index(dragEl);
+
+          do {
+            dragIndex -= direction;
+            sibling = parentEl.children[dragIndex];
+          } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
+        } // If dragEl is already beside target: Do not insert
+
+
+        if (direction === 0 || sibling === target) {
+          return completed(false);
+        }
+
+        lastTarget = target;
+        lastDirection = direction;
+        var nextSibling = target.nextElementSibling,
+            after = false;
+        after = direction === 1;
+
+        var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
+
+        if (moveVector !== false) {
+          if (moveVector === 1 || moveVector === -1) {
+            after = moveVector === 1;
+          }
+
+          _silent = true;
+          setTimeout(_unsilent, 30);
+          capture();
+
+          if (after && !nextSibling) {
+            el.appendChild(dragEl);
+          } else {
+            target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
+          } // Undo chrome's scroll adjustment (has no effect on other browsers)
+
+
+          if (scrolledPastTop) {
+            scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
+          }
+
+          parentEl = dragEl.parentNode; // actualization
+          // must be done before animation
+
+          if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
+            targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
+          }
+
+          changed();
+          return completed(true);
+        }
+      }
+
+      if (el.contains(dragEl)) {
+        return completed(false);
+      }
+    }
+
+    return false;
+  },
+  _ignoreWhileAnimating: null,
+  _offMoveEvents: function _offMoveEvents() {
+    off(document, 'mousemove', this._onTouchMove);
+    off(document, 'touchmove', this._onTouchMove);
+    off(document, 'pointermove', this._onTouchMove);
+    off(document, 'dragover', nearestEmptyInsertDetectEvent);
+    off(document, 'mousemove', nearestEmptyInsertDetectEvent);
+    off(document, 'touchmove', nearestEmptyInsertDetectEvent);
+  },
+  _offUpEvents: function _offUpEvents() {
+    var ownerDocument = this.el.ownerDocument;
+    off(ownerDocument, 'mouseup', this._onDrop);
+    off(ownerDocument, 'touchend', this._onDrop);
+    off(ownerDocument, 'pointerup', this._onDrop);
+    off(ownerDocument, 'touchcancel', this._onDrop);
+    off(document, 'selectstart', this);
+  },
+  _onDrop: function _onDrop(
+  /**Event*/
+  evt) {
+    var el = this.el,
+        options = this.options; // Get the index of the dragged element within its parent
+
+    newIndex = index(dragEl);
+    newDraggableIndex = index(dragEl, options.draggable);
+    pluginEvent('drop', this, {
+      evt: evt
+    });
+    parentEl = dragEl && dragEl.parentNode; // Get again after plugin event
+
+    newIndex = index(dragEl);
+    newDraggableIndex = index(dragEl, options.draggable);
+
+    if (Sortable.eventCanceled) {
+      this._nulling();
+
+      return;
+    }
+
+    awaitingDragStarted = false;
+    isCircumstantialInvert = false;
+    pastFirstInvertThresh = false;
+    clearInterval(this._loopId);
+    clearTimeout(this._dragStartTimer);
+
+    _cancelNextTick(this.cloneId);
+
+    _cancelNextTick(this._dragStartId); // Unbind events
+
+
+    if (this.nativeDraggable) {
+      off(document, 'drop', this);
+      off(el, 'dragstart', this._onDragStart);
+    }
+
+    this._offMoveEvents();
+
+    this._offUpEvents();
+
+    if (Safari) {
+      css(document.body, 'user-select', '');
+    }
+
+    css(dragEl, 'transform', '');
+
+    if (evt) {
+      if (moved) {
+        evt.cancelable && evt.preventDefault();
+        !options.dropBubble && evt.stopPropagation();
+      }
+
+      ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
+
+      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+        // Remove clone(s)
+        cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
+      }
+
+      if (dragEl) {
+        if (this.nativeDraggable) {
+          off(dragEl, 'dragend', this);
+        }
+
+        _disableDraggable(dragEl);
+
+        dragEl.style['will-change'] = ''; // Remove classes
+        // ghostClass is added in dragStarted
+
+        if (moved && !awaitingDragStarted) {
+          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
+        }
+
+        toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
+
+        _dispatchEvent({
+          sortable: this,
+          name: 'unchoose',
+          toEl: parentEl,
+          newIndex: null,
+          newDraggableIndex: null,
+          originalEvent: evt
+        });
+
+        if (rootEl !== parentEl) {
+          if (newIndex >= 0) {
+            // Add event
+            _dispatchEvent({
+              rootEl: parentEl,
+              name: 'add',
+              toEl: parentEl,
+              fromEl: rootEl,
+              originalEvent: evt
+            }); // Remove event
+
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'remove',
+              toEl: parentEl,
+              originalEvent: evt
+            }); // drag from one list and drop into another
+
+
+            _dispatchEvent({
+              rootEl: parentEl,
+              name: 'sort',
+              toEl: parentEl,
+              fromEl: rootEl,
+              originalEvent: evt
+            });
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'sort',
+              toEl: parentEl,
+              originalEvent: evt
+            });
+          }
+
+          putSortable && putSortable.save();
+        } else {
+          if (newIndex !== oldIndex) {
+            if (newIndex >= 0) {
+              // drag & drop within the same list
+              _dispatchEvent({
+                sortable: this,
+                name: 'update',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+
+              _dispatchEvent({
+                sortable: this,
+                name: 'sort',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+            }
+          }
+        }
+
+        if (Sortable.active) {
+          /* jshint eqnull:true */
+          if (newIndex == null || newIndex === -1) {
+            newIndex = oldIndex;
+            newDraggableIndex = oldDraggableIndex;
+          }
+
+          _dispatchEvent({
+            sortable: this,
+            name: 'end',
+            toEl: parentEl,
+            originalEvent: evt
+          }); // Save sorting
+
+
+          this.save();
+        }
+      }
+    }
+
+    this._nulling();
+  },
+  _nulling: function _nulling() {
+    pluginEvent('nulling', this);
+    rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
+    savedInputChecked.forEach(function (el) {
+      el.checked = true;
+    });
+    savedInputChecked.length = lastDx = lastDy = 0;
+  },
+  handleEvent: function handleEvent(
+  /**Event*/
+  evt) {
+    switch (evt.type) {
+      case 'drop':
+      case 'dragend':
+        this._onDrop(evt);
+
+        break;
+
+      case 'dragenter':
+      case 'dragover':
+        if (dragEl) {
+          this._onDragOver(evt);
+
+          _globalDragOver(evt);
+        }
+
+        break;
+
+      case 'selectstart':
+        evt.preventDefault();
+        break;
+    }
+  },
+
+  /**
+   * Serializes the item into an array of string.
+   * @returns {String[]}
+   */
+  toArray: function toArray() {
+    var order = [],
+        el,
+        children = this.el.children,
+        i = 0,
+        n = children.length,
+        options = this.options;
+
+    for (; i < n; i++) {
+      el = children[i];
+
+      if (closest(el, options.draggable, this.el, false)) {
+        order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
+      }
+    }
+
+    return order;
+  },
+
+  /**
+   * Sorts the elements according to the array.
+   * @param  {String[]}  order  order of the items
+   */
+  sort: function sort(order) {
+    var items = {},
+        rootEl = this.el;
+    this.toArray().forEach(function (id, i) {
+      var el = rootEl.children[i];
+
+      if (closest(el, this.options.draggable, rootEl, false)) {
+        items[id] = el;
+      }
+    }, this);
+    order.forEach(function (id) {
+      if (items[id]) {
+        rootEl.removeChild(items[id]);
+        rootEl.appendChild(items[id]);
+      }
+    });
+  },
+
+  /**
+   * Save the current sorting
+   */
+  save: function save() {
+    var store = this.options.store;
+    store && store.set && store.set(this);
+  },
+
+  /**
+   * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+   * @param   {HTMLElement}  el
+   * @param   {String}       [selector]  default: `options.draggable`
+   * @returns {HTMLElement|null}
+   */
+  closest: function closest$1(el, selector) {
+    return closest(el, selector || this.options.draggable, this.el, false);
+  },
+
+  /**
+   * Set/get option
+   * @param   {string} name
+   * @param   {*}      [value]
+   * @returns {*}
+   */
+  option: function option(name, value) {
+    var options = this.options;
+
+    if (value === void 0) {
+      return options[name];
+    } else {
+      var modifiedValue = PluginManager.modifyOption(this, name, value);
+
+      if (typeof modifiedValue !== 'undefined') {
+        options[name] = modifiedValue;
+      } else {
+        options[name] = value;
+      }
+
+      if (name === 'group') {
+        _prepareGroup(options);
+      }
+    }
+  },
+
+  /**
+   * Destroy
+   */
+  destroy: function destroy() {
+    pluginEvent('destroy', this);
+    var el = this.el;
+    el[expando] = null;
+    off(el, 'mousedown', this._onTapStart);
+    off(el, 'touchstart', this._onTapStart);
+    off(el, 'pointerdown', this._onTapStart);
+
+    if (this.nativeDraggable) {
+      off(el, 'dragover', this);
+      off(el, 'dragenter', this);
+    } // Remove draggable attributes
+
+
+    Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
+      el.removeAttribute('draggable');
+    });
+
+    this._onDrop();
+
+    this._disableDelayedDragEvents();
+
+    sortables.splice(sortables.indexOf(this.el), 1);
+    this.el = el = null;
+  },
+  _hideClone: function _hideClone() {
+    if (!cloneHidden) {
+      pluginEvent('hideClone', this);
+      if (Sortable.eventCanceled) return;
+      css(cloneEl, 'display', 'none');
+
+      if (this.options.removeCloneOnHide && cloneEl.parentNode) {
+        cloneEl.parentNode.removeChild(cloneEl);
+      }
+
+      cloneHidden = true;
+    }
+  },
+  _showClone: function _showClone(putSortable) {
+    if (putSortable.lastPutMode !== 'clone') {
+      this._hideClone();
+
+      return;
+    }
+
+    if (cloneHidden) {
+      pluginEvent('showClone', this);
+      if (Sortable.eventCanceled) return; // show clone at dragEl or original position
+
+      if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
+        rootEl.insertBefore(cloneEl, dragEl);
+      } else if (nextEl) {
+        rootEl.insertBefore(cloneEl, nextEl);
+      } else {
+        rootEl.appendChild(cloneEl);
+      }
+
+      if (this.options.group.revertClone) {
+        this.animate(dragEl, cloneEl);
+      }
+
+      css(cloneEl, 'display', '');
+      cloneHidden = false;
+    }
+  }
+};
+
+function _globalDragOver(
+/**Event*/
+evt) {
+  if (evt.dataTransfer) {
+    evt.dataTransfer.dropEffect = 'move';
+  }
+
+  evt.cancelable && evt.preventDefault();
+}
+
+function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
+  var evt,
+      sortable = fromEl[expando],
+      onMoveFn = sortable.options.onMove,
+      retVal; // Support for new CustomEvent feature
+
+  if (window.CustomEvent && !IE11OrLess && !Edge) {
+    evt = new CustomEvent('move', {
+      bubbles: true,
+      cancelable: true
+    });
+  } else {
+    evt = document.createEvent('Event');
+    evt.initEvent('move', true, true);
+  }
+
+  evt.to = toEl;
+  evt.from = fromEl;
+  evt.dragged = dragEl;
+  evt.draggedRect = dragRect;
+  evt.related = targetEl || toEl;
+  evt.relatedRect = targetRect || getRect(toEl);
+  evt.willInsertAfter = willInsertAfter;
+  evt.originalEvent = originalEvent;
+  fromEl.dispatchEvent(evt);
+
+  if (onMoveFn) {
+    retVal = onMoveFn.call(sortable, evt, originalEvent);
+  }
+
+  return retVal;
+}
+
+function _disableDraggable(el) {
+  el.draggable = false;
+}
+
+function _unsilent() {
+  _silent = false;
+}
+
+function _ghostIsLast(evt, vertical, sortable) {
+  var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
+  var spacer = 10;
+  return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
+}
+
+function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
+  var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
+      targetLength = vertical ? targetRect.height : targetRect.width,
+      targetS1 = vertical ? targetRect.top : targetRect.left,
+      targetS2 = vertical ? targetRect.bottom : targetRect.right,
+      invert = false;
+
+  if (!invertSwap) {
+    // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
+    if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
+      // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
+      // check if past first invert threshold on side opposite of lastDirection
+      if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
+        // past first invert threshold, do not restrict inverted threshold to dragEl shadow
+        pastFirstInvertThresh = true;
+      }
+
+      if (!pastFirstInvertThresh) {
+        // dragEl shadow (target move distance shadow)
+        if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
+        : mouseOnAxis > targetS2 - targetMoveDistance) {
+          return -lastDirection;
+        }
+      } else {
+        invert = true;
+      }
+    } else {
+      // Regular
+      if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
+        return _getInsertDirection(target);
+      }
+    }
+  }
+
+  invert = invert || invertSwap;
+
+  if (invert) {
+    // Invert of regular
+    if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
+      return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
+    }
+  }
+
+  return 0;
+}
+/**
+ * Gets the direction dragEl must be swapped relative to target in order to make it
+ * seem that dragEl has been "inserted" into that element's position
+ * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
+ * @return {Number}                   Direction dragEl must be swapped
+ */
+
+
+function _getInsertDirection(target) {
+  if (index(dragEl) < index(target)) {
+    return 1;
+  } else {
+    return -1;
+  }
+}
+/**
+ * Generate id
+ * @param   {HTMLElement} el
+ * @returns {String}
+ * @private
+ */
+
+
+function _generateId(el) {
+  var str = el.tagName + el.className + el.src + el.href + el.textContent,
+      i = str.length,
+      sum = 0;
+
+  while (i--) {
+    sum += str.charCodeAt(i);
+  }
+
+  return sum.toString(36);
+}
+
+function _saveInputCheckedState(root) {
+  savedInputChecked.length = 0;
+  var inputs = root.getElementsByTagName('input');
+  var idx = inputs.length;
+
+  while (idx--) {
+    var el = inputs[idx];
+    el.checked && savedInputChecked.push(el);
+  }
+}
+
+function _nextTick(fn) {
+  return setTimeout(fn, 0);
+}
+
+function _cancelNextTick(id) {
+  return clearTimeout(id);
+} // Fixed #973:
+
+
+if (documentExists) {
+  on(document, 'touchmove', function (evt) {
+    if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
+      evt.preventDefault();
+    }
+  });
+} // Export utils
+
+
+Sortable.utils = {
+  on: on,
+  off: off,
+  css: css,
+  find: find,
+  is: function is(el, selector) {
+    return !!closest(el, selector, el, false);
+  },
+  extend: extend,
+  throttle: throttle,
+  closest: closest,
+  toggleClass: toggleClass,
+  clone: clone,
+  index: index,
+  nextTick: _nextTick,
+  cancelNextTick: _cancelNextTick,
+  detectDirection: _detectDirection,
+  getChild: getChild
+};
+/**
+ * Get the Sortable instance of an element
+ * @param  {HTMLElement} element The element
+ * @return {Sortable|undefined}         The instance of Sortable
+ */
+
+Sortable.get = function (element) {
+  return element[expando];
+};
+/**
+ * Mount a plugin to Sortable
+ * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
+ */
+
+
+Sortable.mount = function () {
+  for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
+    plugins[_key] = arguments[_key];
+  }
+
+  if (plugins[0].constructor === Array) plugins = plugins[0];
+  plugins.forEach(function (plugin) {
+    if (!plugin.prototype || !plugin.prototype.constructor) {
+      throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
+    }
+
+    if (plugin.utils) Sortable.utils = _objectSpread({}, Sortable.utils, plugin.utils);
+    PluginManager.mount(plugin);
+  });
+};
+/**
+ * Create sortable instance
+ * @param {HTMLElement}  el
+ * @param {Object}      [options]
+ */
+
+
+Sortable.create = function (el, options) {
+  return new Sortable(el, options);
+}; // Export
+
+
+Sortable.version = version;
+
+var autoScrolls = [],
+    scrollEl,
+    scrollRootEl,
+    scrolling = false,
+    lastAutoScrollX,
+    lastAutoScrollY,
+    touchEvt$1,
+    pointerElemChangedInterval;
+
+function AutoScrollPlugin() {
+  function AutoScroll() {
+    this.defaults = {
+      scroll: true,
+      scrollSensitivity: 30,
+      scrollSpeed: 10,
+      bubbleScroll: true
+    }; // Bind all private methods
+
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    }
+  }
+
+  AutoScroll.prototype = {
+    dragStarted: function dragStarted(_ref) {
+      var originalEvent = _ref.originalEvent;
+
+      if (this.sortable.nativeDraggable) {
+        on(document, 'dragover', this._handleAutoScroll);
+      } else {
+        if (this.options.supportPointer) {
+          on(document, 'pointermove', this._handleFallbackAutoScroll);
+        } else if (originalEvent.touches) {
+          on(document, 'touchmove', this._handleFallbackAutoScroll);
+        } else {
+          on(document, 'mousemove', this._handleFallbackAutoScroll);
+        }
+      }
+    },
+    dragOverCompleted: function dragOverCompleted(_ref2) {
+      var originalEvent = _ref2.originalEvent;
+
+      // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
+      if (!this.options.dragOverBubble && !originalEvent.rootEl) {
+        this._handleAutoScroll(originalEvent);
+      }
+    },
+    drop: function drop() {
+      if (this.sortable.nativeDraggable) {
+        off(document, 'dragover', this._handleAutoScroll);
+      } else {
+        off(document, 'pointermove', this._handleFallbackAutoScroll);
+        off(document, 'touchmove', this._handleFallbackAutoScroll);
+        off(document, 'mousemove', this._handleFallbackAutoScroll);
+      }
+
+      clearPointerElemChangedInterval();
+      clearAutoScrolls();
+      cancelThrottle();
+    },
+    nulling: function nulling() {
+      touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
+      autoScrolls.length = 0;
+    },
+    _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
+      this._handleAutoScroll(evt, true);
+    },
+    _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
+      var _this = this;
+
+      var x = (evt.touches ? evt.touches[0] : evt).clientX,
+          y = (evt.touches ? evt.touches[0] : evt).clientY,
+          elem = document.elementFromPoint(x, y);
+      touchEvt$1 = evt; // IE does not seem to have native autoscroll,
+      // Edge's autoscroll seems too conditional,
+      // MACOS Safari does not have autoscroll,
+      // Firefox and Chrome are good
+
+      if (fallback || Edge || IE11OrLess || Safari) {
+        autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
+
+        var ogElemScroller = getParentAutoScrollElement(elem, true);
+
+        if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
+          pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
+
+          pointerElemChangedInterval = setInterval(function () {
+            var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
+
+            if (newElem !== ogElemScroller) {
+              ogElemScroller = newElem;
+              clearAutoScrolls();
+            }
+
+            autoScroll(evt, _this.options, newElem, fallback);
+          }, 10);
+          lastAutoScrollX = x;
+          lastAutoScrollY = y;
+        }
+      } else {
+        // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
+        if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
+          clearAutoScrolls();
+          return;
+        }
+
+        autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
+      }
+    }
+  };
+  return _extends(AutoScroll, {
+    pluginName: 'scroll',
+    initializeByDefault: true
+  });
+}
+
+function clearAutoScrolls() {
+  autoScrolls.forEach(function (autoScroll) {
+    clearInterval(autoScroll.pid);
+  });
+  autoScrolls = [];
+}
+
+function clearPointerElemChangedInterval() {
+  clearInterval(pointerElemChangedInterval);
+}
+
+var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
+  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+  if (!options.scroll) return;
+  var x = (evt.touches ? evt.touches[0] : evt).clientX,
+      y = (evt.touches ? evt.touches[0] : evt).clientY,
+      sens = options.scrollSensitivity,
+      speed = options.scrollSpeed,
+      winScroller = getWindowScrollingElement();
+  var scrollThisInstance = false,
+      scrollCustomFn; // New scroll root, set scrollEl
+
+  if (scrollRootEl !== rootEl) {
+    scrollRootEl = rootEl;
+    clearAutoScrolls();
+    scrollEl = options.scroll;
+    scrollCustomFn = options.scrollFn;
+
+    if (scrollEl === true) {
+      scrollEl = getParentAutoScrollElement(rootEl, true);
+    }
+  }
+
+  var layersOut = 0;
+  var currentParent = scrollEl;
+
+  do {
+    var el = currentParent,
+        rect = getRect(el),
+        top = rect.top,
+        bottom = rect.bottom,
+        left = rect.left,
+        right = rect.right,
+        width = rect.width,
+        height = rect.height,
+        canScrollX = void 0,
+        canScrollY = void 0,
+        scrollWidth = el.scrollWidth,
+        scrollHeight = el.scrollHeight,
+        elCSS = css(el),
+        scrollPosX = el.scrollLeft,
+        scrollPosY = el.scrollTop;
+
+    if (el === winScroller) {
+      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
+      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
+    } else {
+      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
+      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
+    }
+
+    var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
+    var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
+
+    if (!autoScrolls[layersOut]) {
+      for (var i = 0; i <= layersOut; i++) {
+        if (!autoScrolls[i]) {
+          autoScrolls[i] = {};
+        }
+      }
+    }
+
+    if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
+      autoScrolls[layersOut].el = el;
+      autoScrolls[layersOut].vx = vx;
+      autoScrolls[layersOut].vy = vy;
+      clearInterval(autoScrolls[layersOut].pid);
+
+      if (vx != 0 || vy != 0) {
+        scrollThisInstance = true;
+        /* jshint loopfunc:true */
+
+        autoScrolls[layersOut].pid = setInterval(function () {
+          // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
+          if (isFallback && this.layer === 0) {
+            Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
+
+          }
+
+          var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
+          var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
+
+          if (typeof scrollCustomFn === 'function') {
+            if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
+              return;
+            }
+          }
+
+          scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
+        }.bind({
+          layer: layersOut
+        }), 24);
+      }
+    }
+
+    layersOut++;
+  } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
+
+  scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
+}, 30);
+
+var drop = function drop(_ref) {
+  var originalEvent = _ref.originalEvent,
+      putSortable = _ref.putSortable,
+      dragEl = _ref.dragEl,
+      activeSortable = _ref.activeSortable,
+      dispatchSortableEvent = _ref.dispatchSortableEvent,
+      hideGhostForTarget = _ref.hideGhostForTarget,
+      unhideGhostForTarget = _ref.unhideGhostForTarget;
+  if (!originalEvent) return;
+  var toSortable = putSortable || activeSortable;
+  hideGhostForTarget();
+  var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
+  var target = document.elementFromPoint(touch.clientX, touch.clientY);
+  unhideGhostForTarget();
+
+  if (toSortable && !toSortable.el.contains(target)) {
+    dispatchSortableEvent('spill');
+    this.onSpill({
+      dragEl: dragEl,
+      putSortable: putSortable
+    });
+  }
+};
+
+function Revert() {}
+
+Revert.prototype = {
+  startIndex: null,
+  dragStart: function dragStart(_ref2) {
+    var oldDraggableIndex = _ref2.oldDraggableIndex;
+    this.startIndex = oldDraggableIndex;
+  },
+  onSpill: function onSpill(_ref3) {
+    var dragEl = _ref3.dragEl,
+        putSortable = _ref3.putSortable;
+    this.sortable.captureAnimationState();
+
+    if (putSortable) {
+      putSortable.captureAnimationState();
+    }
+
+    var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
+
+    if (nextSibling) {
+      this.sortable.el.insertBefore(dragEl, nextSibling);
+    } else {
+      this.sortable.el.appendChild(dragEl);
+    }
+
+    this.sortable.animateAll();
+
+    if (putSortable) {
+      putSortable.animateAll();
+    }
+  },
+  drop: drop
+};
+
+_extends(Revert, {
+  pluginName: 'revertOnSpill'
+});
+
+function Remove() {}
+
+Remove.prototype = {
+  onSpill: function onSpill(_ref4) {
+    var dragEl = _ref4.dragEl,
+        putSortable = _ref4.putSortable;
+    var parentSortable = putSortable || this.sortable;
+    parentSortable.captureAnimationState();
+    dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
+    parentSortable.animateAll();
+  },
+  drop: drop
+};
+
+_extends(Remove, {
+  pluginName: 'removeOnSpill'
+});
+
+var OnSpill = [Remove, Revert];
+
+var lastSwapEl;
+
+function SwapPlugin() {
+  function Swap() {
+    this.defaults = {
+      swapClass: 'sortable-swap-highlight'
+    };
+  }
+
+  Swap.prototype = {
+    dragStart: function dragStart(_ref) {
+      var dragEl = _ref.dragEl;
+      lastSwapEl = dragEl;
+    },
+    dragOverValid: function dragOverValid(_ref2) {
+      var completed = _ref2.completed,
+          target = _ref2.target,
+          onMove = _ref2.onMove,
+          activeSortable = _ref2.activeSortable,
+          changed = _ref2.changed,
+          cancel = _ref2.cancel;
+      if (!activeSortable.options.swap) return;
+      var el = this.sortable.el,
+          options = this.options;
+
+      if (target && target !== el) {
+        var prevSwapEl = lastSwapEl;
+
+        if (onMove(target) !== false) {
+          toggleClass(target, options.swapClass, true);
+          lastSwapEl = target;
+        } else {
+          lastSwapEl = null;
+        }
+
+        if (prevSwapEl && prevSwapEl !== lastSwapEl) {
+          toggleClass(prevSwapEl, options.swapClass, false);
+        }
+      }
+
+      changed();
+      completed(true);
+      cancel();
+    },
+    drop: function drop(_ref3) {
+      var activeSortable = _ref3.activeSortable,
+          putSortable = _ref3.putSortable,
+          dragEl = _ref3.dragEl;
+      var toSortable = putSortable || this.sortable;
+      var options = this.options;
+      lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
+
+      if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
+        if (dragEl !== lastSwapEl) {
+          toSortable.captureAnimationState();
+          if (toSortable !== activeSortable) activeSortable.captureAnimationState();
+          swapNodes(dragEl, lastSwapEl);
+          toSortable.animateAll();
+          if (toSortable !== activeSortable) activeSortable.animateAll();
+        }
+      }
+    },
+    nulling: function nulling() {
+      lastSwapEl = null;
+    }
+  };
+  return _extends(Swap, {
+    pluginName: 'swap',
+    eventProperties: function eventProperties() {
+      return {
+        swapItem: lastSwapEl
+      };
+    }
+  });
+}
+
+function swapNodes(n1, n2) {
+  var p1 = n1.parentNode,
+      p2 = n2.parentNode,
+      i1,
+      i2;
+  if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
+  i1 = index(n1);
+  i2 = index(n2);
+
+  if (p1.isEqualNode(p2) && i1 < i2) {
+    i2++;
+  }
+
+  p1.insertBefore(n2, p1.children[i1]);
+  p2.insertBefore(n1, p2.children[i2]);
+}
+
+var multiDragElements = [],
+    multiDragClones = [],
+    lastMultiDragSelect,
+    // for selection with modifier key down (SHIFT)
+multiDragSortable,
+    initialFolding = false,
+    // Initial multi-drag fold when drag started
+folding = false,
+    // Folding any other time
+dragStarted = false,
+    dragEl$1,
+    clonesFromRect,
+    clonesHidden;
+
+function MultiDragPlugin() {
+  function MultiDrag(sortable) {
+    // Bind all private methods
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    }
+
+    if (sortable.options.supportPointer) {
+      on(document, 'pointerup', this._deselectMultiDrag);
+    } else {
+      on(document, 'mouseup', this._deselectMultiDrag);
+      on(document, 'touchend', this._deselectMultiDrag);
+    }
+
+    on(document, 'keydown', this._checkKeyDown);
+    on(document, 'keyup', this._checkKeyUp);
+    this.defaults = {
+      selectedClass: 'sortable-selected',
+      multiDragKey: null,
+      setData: function setData(dataTransfer, dragEl) {
+        var data = '';
+
+        if (multiDragElements.length && multiDragSortable === sortable) {
+          multiDragElements.forEach(function (multiDragElement, i) {
+            data += (!i ? '' : ', ') + multiDragElement.textContent;
+          });
+        } else {
+          data = dragEl.textContent;
+        }
+
+        dataTransfer.setData('Text', data);
+      }
+    };
+  }
+
+  MultiDrag.prototype = {
+    multiDragKeyDown: false,
+    isMultiDrag: false,
+    delayStartGlobal: function delayStartGlobal(_ref) {
+      var dragged = _ref.dragEl;
+      dragEl$1 = dragged;
+    },
+    delayEnded: function delayEnded() {
+      this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
+    },
+    setupClone: function setupClone(_ref2) {
+      var sortable = _ref2.sortable,
+          cancel = _ref2.cancel;
+      if (!this.isMultiDrag) return;
+
+      for (var i = 0; i < multiDragElements.length; i++) {
+        multiDragClones.push(clone(multiDragElements[i]));
+        multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
+        multiDragClones[i].draggable = false;
+        multiDragClones[i].style['will-change'] = '';
+        toggleClass(multiDragClones[i], this.options.selectedClass, false);
+        multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
+      }
+
+      sortable._hideClone();
+
+      cancel();
+    },
+    clone: function clone(_ref3) {
+      var sortable = _ref3.sortable,
+          rootEl = _ref3.rootEl,
+          dispatchSortableEvent = _ref3.dispatchSortableEvent,
+          cancel = _ref3.cancel;
+      if (!this.isMultiDrag) return;
+
+      if (!this.options.removeCloneOnHide) {
+        if (multiDragElements.length && multiDragSortable === sortable) {
+          insertMultiDragClones(true, rootEl);
+          dispatchSortableEvent('clone');
+          cancel();
+        }
+      }
+    },
+    showClone: function showClone(_ref4) {
+      var cloneNowShown = _ref4.cloneNowShown,
+          rootEl = _ref4.rootEl,
+          cancel = _ref4.cancel;
+      if (!this.isMultiDrag) return;
+      insertMultiDragClones(false, rootEl);
+      multiDragClones.forEach(function (clone) {
+        css(clone, 'display', '');
+      });
+      cloneNowShown();
+      clonesHidden = false;
+      cancel();
+    },
+    hideClone: function hideClone(_ref5) {
+      var _this = this;
+
+      var sortable = _ref5.sortable,
+          cloneNowHidden = _ref5.cloneNowHidden,
+          cancel = _ref5.cancel;
+      if (!this.isMultiDrag) return;
+      multiDragClones.forEach(function (clone) {
+        css(clone, 'display', 'none');
+
+        if (_this.options.removeCloneOnHide && clone.parentNode) {
+          clone.parentNode.removeChild(clone);
+        }
+      });
+      cloneNowHidden();
+      clonesHidden = true;
+      cancel();
+    },
+    dragStartGlobal: function dragStartGlobal(_ref6) {
+      var sortable = _ref6.sortable;
+
+      if (!this.isMultiDrag && multiDragSortable) {
+        multiDragSortable.multiDrag._deselectMultiDrag();
+      }
+
+      multiDragElements.forEach(function (multiDragElement) {
+        multiDragElement.sortableIndex = index(multiDragElement);
+      }); // Sort multi-drag elements
+
+      multiDragElements = multiDragElements.sort(function (a, b) {
+        return a.sortableIndex - b.sortableIndex;
+      });
+      dragStarted = true;
+    },
+    dragStarted: function dragStarted(_ref7) {
+      var _this2 = this;
+
+      var sortable = _ref7.sortable;
+      if (!this.isMultiDrag) return;
+
+      if (this.options.sort) {
+        // Capture rects,
+        // hide multi drag elements (by positioning them absolute),
+        // set multi drag elements rects to dragRect,
+        // show multi drag elements,
+        // animate to rects,
+        // unset rects & remove from DOM
+        sortable.captureAnimationState();
+
+        if (this.options.animation) {
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            css(multiDragElement, 'position', 'absolute');
+          });
+          var dragRect = getRect(dragEl$1, false, true, true);
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            setRect(multiDragElement, dragRect);
+          });
+          folding = true;
+          initialFolding = true;
+        }
+      }
+
+      sortable.animateAll(function () {
+        folding = false;
+        initialFolding = false;
+
+        if (_this2.options.animation) {
+          multiDragElements.forEach(function (multiDragElement) {
+            unsetRect(multiDragElement);
+          });
+        } // Remove all auxiliary multidrag items from el, if sorting enabled
+
+
+        if (_this2.options.sort) {
+          removeMultiDragElements();
+        }
+      });
+    },
+    dragOver: function dragOver(_ref8) {
+      var target = _ref8.target,
+          completed = _ref8.completed,
+          cancel = _ref8.cancel;
+
+      if (folding && ~multiDragElements.indexOf(target)) {
+        completed(false);
+        cancel();
+      }
+    },
+    revert: function revert(_ref9) {
+      var fromSortable = _ref9.fromSortable,
+          rootEl = _ref9.rootEl,
+          sortable = _ref9.sortable,
+          dragRect = _ref9.dragRect;
+
+      if (multiDragElements.length > 1) {
+        // Setup unfold animation
+        multiDragElements.forEach(function (multiDragElement) {
+          sortable.addAnimationState({
+            target: multiDragElement,
+            rect: folding ? getRect(multiDragElement) : dragRect
+          });
+          unsetRect(multiDragElement);
+          multiDragElement.fromRect = dragRect;
+          fromSortable.removeAnimationState(multiDragElement);
+        });
+        folding = false;
+        insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
+      }
+    },
+    dragOverCompleted: function dragOverCompleted(_ref10) {
+      var sortable = _ref10.sortable,
+          isOwner = _ref10.isOwner,
+          insertion = _ref10.insertion,
+          activeSortable = _ref10.activeSortable,
+          parentEl = _ref10.parentEl,
+          putSortable = _ref10.putSortable;
+      var options = this.options;
+
+      if (insertion) {
+        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+        if (isOwner) {
+          activeSortable._hideClone();
+        }
+
+        initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location
+
+        if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
+          // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
+          var dragRectAbsolute = getRect(dragEl$1, false, true, true);
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
+            // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
+
+            parentEl.appendChild(multiDragElement);
+          });
+          folding = true;
+        } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
+
+
+        if (!isOwner) {
+          // Only remove if not folding (folding will remove them anyways)
+          if (!folding) {
+            removeMultiDragElements();
+          }
+
+          if (multiDragElements.length > 1) {
+            var clonesHiddenBefore = clonesHidden;
+
+            activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden
+
+
+            if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
+              multiDragClones.forEach(function (clone) {
+                activeSortable.addAnimationState({
+                  target: clone,
+                  rect: clonesFromRect
+                });
+                clone.fromRect = clonesFromRect;
+                clone.thisAnimationDuration = null;
+              });
+            }
+          } else {
+            activeSortable._showClone(sortable);
+          }
+        }
+      }
+    },
+    dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
+      var dragRect = _ref11.dragRect,
+          isOwner = _ref11.isOwner,
+          activeSortable = _ref11.activeSortable;
+      multiDragElements.forEach(function (multiDragElement) {
+        multiDragElement.thisAnimationDuration = null;
+      });
+
+      if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
+        clonesFromRect = _extends({}, dragRect);
+        var dragMatrix = matrix(dragEl$1, true);
+        clonesFromRect.top -= dragMatrix.f;
+        clonesFromRect.left -= dragMatrix.e;
+      }
+    },
+    dragOverAnimationComplete: function dragOverAnimationComplete() {
+      if (folding) {
+        folding = false;
+        removeMultiDragElements();
+      }
+    },
+    drop: function drop(_ref12) {
+      var evt = _ref12.originalEvent,
+          rootEl = _ref12.rootEl,
+          parentEl = _ref12.parentEl,
+          sortable = _ref12.sortable,
+          dispatchSortableEvent = _ref12.dispatchSortableEvent,
+          oldIndex = _ref12.oldIndex,
+          putSortable = _ref12.putSortable;
+      var toSortable = putSortable || this.sortable;
+      if (!evt) return;
+      var options = this.options,
+          children = parentEl.children; // Multi-drag selection
+
+      if (!dragStarted) {
+        if (options.multiDragKey && !this.multiDragKeyDown) {
+          this._deselectMultiDrag();
+        }
+
+        toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
+
+        if (!~multiDragElements.indexOf(dragEl$1)) {
+          multiDragElements.push(dragEl$1);
+          dispatchEvent({
+            sortable: sortable,
+            rootEl: rootEl,
+            name: 'select',
+            targetEl: dragEl$1,
+            originalEvt: evt
+          }); // Modifier activated, select from last to dragEl
+
+          if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
+            var lastIndex = index(lastMultiDragSelect),
+                currentIndex = index(dragEl$1);
+
+            if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
+              // Must include lastMultiDragSelect (select it), in case modified selection from no selection
+              // (but previous selection existed)
+              var n, i;
+
+              if (currentIndex > lastIndex) {
+                i = lastIndex;
+                n = currentIndex;
+              } else {
+                i = currentIndex;
+                n = lastIndex + 1;
+              }
+
+              for (; i < n; i++) {
+                if (~multiDragElements.indexOf(children[i])) continue;
+                toggleClass(children[i], options.selectedClass, true);
+                multiDragElements.push(children[i]);
+                dispatchEvent({
+                  sortable: sortable,
+                  rootEl: rootEl,
+                  name: 'select',
+                  targetEl: children[i],
+                  originalEvt: evt
+                });
+              }
+            }
+          } else {
+            lastMultiDragSelect = dragEl$1;
+          }
+
+          multiDragSortable = toSortable;
+        } else {
+          multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
+          lastMultiDragSelect = null;
+          dispatchEvent({
+            sortable: sortable,
+            rootEl: rootEl,
+            name: 'deselect',
+            targetEl: dragEl$1,
+            originalEvt: evt
+          });
+        }
+      } // Multi-drag drop
+
+
+      if (dragStarted && this.isMultiDrag) {
+        // Do not "unfold" after around dragEl if reverted
+        if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
+          var dragRect = getRect(dragEl$1),
+              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
+          if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
+          toSortable.captureAnimationState();
+
+          if (!initialFolding) {
+            if (options.animation) {
+              dragEl$1.fromRect = dragRect;
+              multiDragElements.forEach(function (multiDragElement) {
+                multiDragElement.thisAnimationDuration = null;
+
+                if (multiDragElement !== dragEl$1) {
+                  var rect = folding ? getRect(multiDragElement) : dragRect;
+                  multiDragElement.fromRect = rect; // Prepare unfold animation
+
+                  toSortable.addAnimationState({
+                    target: multiDragElement,
+                    rect: rect
+                  });
+                }
+              });
+            } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
+            // properly they must all be removed
+
+
+            removeMultiDragElements();
+            multiDragElements.forEach(function (multiDragElement) {
+              if (children[multiDragIndex]) {
+                parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
+              } else {
+                parentEl.appendChild(multiDragElement);
+              }
+
+              multiDragIndex++;
+            }); // If initial folding is done, the elements may have changed position because they are now
+            // unfolding around dragEl, even though dragEl may not have his index changed, so update event
+            // must be fired here as Sortable will not.
+
+            if (oldIndex === index(dragEl$1)) {
+              var update = false;
+              multiDragElements.forEach(function (multiDragElement) {
+                if (multiDragElement.sortableIndex !== index(multiDragElement)) {
+                  update = true;
+                  return;
+                }
+              });
+
+              if (update) {
+                dispatchSortableEvent('update');
+              }
+            }
+          } // Must be done after capturing individual rects (scroll bar)
+
+
+          multiDragElements.forEach(function (multiDragElement) {
+            unsetRect(multiDragElement);
+          });
+          toSortable.animateAll();
+        }
+
+        multiDragSortable = toSortable;
+      } // Remove clones if necessary
+
+
+      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+        multiDragClones.forEach(function (clone) {
+          clone.parentNode && clone.parentNode.removeChild(clone);
+        });
+      }
+    },
+    nullingGlobal: function nullingGlobal() {
+      this.isMultiDrag = dragStarted = false;
+      multiDragClones.length = 0;
+    },
+    destroyGlobal: function destroyGlobal() {
+      this._deselectMultiDrag();
+
+      off(document, 'pointerup', this._deselectMultiDrag);
+      off(document, 'mouseup', this._deselectMultiDrag);
+      off(document, 'touchend', this._deselectMultiDrag);
+      off(document, 'keydown', this._checkKeyDown);
+      off(document, 'keyup', this._checkKeyUp);
+    },
+    _deselectMultiDrag: function _deselectMultiDrag(evt) {
+      if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable
+
+      if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable
+
+      if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click
+
+      if (evt && evt.button !== 0) return;
+
+      while (multiDragElements.length) {
+        var el = multiDragElements[0];
+        toggleClass(el, this.options.selectedClass, false);
+        multiDragElements.shift();
+        dispatchEvent({
+          sortable: this.sortable,
+          rootEl: this.sortable.el,
+          name: 'deselect',
+          targetEl: el,
+          originalEvt: evt
+        });
+      }
+    },
+    _checkKeyDown: function _checkKeyDown(evt) {
+      if (evt.key === this.options.multiDragKey) {
+        this.multiDragKeyDown = true;
+      }
+    },
+    _checkKeyUp: function _checkKeyUp(evt) {
+      if (evt.key === this.options.multiDragKey) {
+        this.multiDragKeyDown = false;
+      }
+    }
+  };
+  return _extends(MultiDrag, {
+    // Static methods & properties
+    pluginName: 'multiDrag',
+    utils: {
+      /**
+       * Selects the provided multi-drag item
+       * @param  {HTMLElement} el    The element to be selected
+       */
+      select: function select(el) {
+        var sortable = el.parentNode[expando];
+        if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
+
+        if (multiDragSortable && multiDragSortable !== sortable) {
+          multiDragSortable.multiDrag._deselectMultiDrag();
+
+          multiDragSortable = sortable;
+        }
+
+        toggleClass(el, sortable.options.selectedClass, true);
+        multiDragElements.push(el);
+      },
+
+      /**
+       * Deselects the provided multi-drag item
+       * @param  {HTMLElement} el    The element to be deselected
+       */
+      deselect: function deselect(el) {
+        var sortable = el.parentNode[expando],
+            index = multiDragElements.indexOf(el);
+        if (!sortable || !sortable.options.multiDrag || !~index) return;
+        toggleClass(el, sortable.options.selectedClass, false);
+        multiDragElements.splice(index, 1);
+      }
+    },
+    eventProperties: function eventProperties() {
+      var _this3 = this;
+
+      var oldIndicies = [],
+          newIndicies = [];
+      multiDragElements.forEach(function (multiDragElement) {
+        oldIndicies.push({
+          multiDragElement: multiDragElement,
+          index: multiDragElement.sortableIndex
+        }); // multiDragElements will already be sorted if folding
+
+        var newIndex;
+
+        if (folding && multiDragElement !== dragEl$1) {
+          newIndex = -1;
+        } else if (folding) {
+          newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
+        } else {
+          newIndex = index(multiDragElement);
+        }
+
+        newIndicies.push({
+          multiDragElement: multiDragElement,
+          index: newIndex
+        });
+      });
+      return {
+        items: _toConsumableArray(multiDragElements),
+        clones: [].concat(multiDragClones),
+        oldIndicies: oldIndicies,
+        newIndicies: newIndicies
+      };
+    },
+    optionListeners: {
+      multiDragKey: function multiDragKey(key) {
+        key = key.toLowerCase();
+
+        if (key === 'ctrl') {
+          key = 'Control';
+        } else if (key.length > 1) {
+          key = key.charAt(0).toUpperCase() + key.substr(1);
+        }
+
+        return key;
+      }
+    }
+  });
+}
+
+function insertMultiDragElements(clonesInserted, rootEl) {
+  multiDragElements.forEach(function (multiDragElement, i) {
+    var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
+
+    if (target) {
+      rootEl.insertBefore(multiDragElement, target);
+    } else {
+      rootEl.appendChild(multiDragElement);
+    }
+  });
+}
+/**
+ * Insert multi-drag clones
+ * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
+ * @param  {HTMLElement} rootEl
+ */
+
+
+function insertMultiDragClones(elementsInserted, rootEl) {
+  multiDragClones.forEach(function (clone, i) {
+    var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
+
+    if (target) {
+      rootEl.insertBefore(clone, target);
+    } else {
+      rootEl.appendChild(clone);
+    }
+  });
+}
+
+function removeMultiDragElements() {
+  multiDragElements.forEach(function (multiDragElement) {
+    if (multiDragElement === dragEl$1) return;
+    multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
+  });
+}
+
+export default Sortable;
+export { AutoScrollPlugin as AutoScroll, MultiDragPlugin as MultiDrag, OnSpill, Sortable, SwapPlugin as Swap };

+ 3699 - 0
public/assets/libs/Sortable/modular/sortable.esm.js

@@ -0,0 +1,3699 @@
+/**!
+ * Sortable 1.10.2
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @author	owenm    <owen23355@gmail.com>
+ * @license MIT
+ */
+function _typeof(obj) {
+  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
+    _typeof = function (obj) {
+      return typeof obj;
+    };
+  } else {
+    _typeof = function (obj) {
+      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+    };
+  }
+
+  return _typeof(obj);
+}
+
+function _defineProperty(obj, key, value) {
+  if (key in obj) {
+    Object.defineProperty(obj, key, {
+      value: value,
+      enumerable: true,
+      configurable: true,
+      writable: true
+    });
+  } else {
+    obj[key] = value;
+  }
+
+  return obj;
+}
+
+function _extends() {
+  _extends = Object.assign || function (target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i];
+
+      for (var key in source) {
+        if (Object.prototype.hasOwnProperty.call(source, key)) {
+          target[key] = source[key];
+        }
+      }
+    }
+
+    return target;
+  };
+
+  return _extends.apply(this, arguments);
+}
+
+function _objectSpread(target) {
+  for (var i = 1; i < arguments.length; i++) {
+    var source = arguments[i] != null ? arguments[i] : {};
+    var ownKeys = Object.keys(source);
+
+    if (typeof Object.getOwnPropertySymbols === 'function') {
+      ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
+        return Object.getOwnPropertyDescriptor(source, sym).enumerable;
+      }));
+    }
+
+    ownKeys.forEach(function (key) {
+      _defineProperty(target, key, source[key]);
+    });
+  }
+
+  return target;
+}
+
+function _objectWithoutPropertiesLoose(source, excluded) {
+  if (source == null) return {};
+  var target = {};
+  var sourceKeys = Object.keys(source);
+  var key, i;
+
+  for (i = 0; i < sourceKeys.length; i++) {
+    key = sourceKeys[i];
+    if (excluded.indexOf(key) >= 0) continue;
+    target[key] = source[key];
+  }
+
+  return target;
+}
+
+function _objectWithoutProperties(source, excluded) {
+  if (source == null) return {};
+
+  var target = _objectWithoutPropertiesLoose(source, excluded);
+
+  var key, i;
+
+  if (Object.getOwnPropertySymbols) {
+    var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
+
+    for (i = 0; i < sourceSymbolKeys.length; i++) {
+      key = sourceSymbolKeys[i];
+      if (excluded.indexOf(key) >= 0) continue;
+      if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
+      target[key] = source[key];
+    }
+  }
+
+  return target;
+}
+
+function _toConsumableArray(arr) {
+  return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
+}
+
+function _arrayWithoutHoles(arr) {
+  if (Array.isArray(arr)) {
+    for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
+
+    return arr2;
+  }
+}
+
+function _iterableToArray(iter) {
+  if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
+}
+
+function _nonIterableSpread() {
+  throw new TypeError("Invalid attempt to spread non-iterable instance");
+}
+
+var version = "1.10.2";
+
+function userAgent(pattern) {
+  if (typeof window !== 'undefined' && window.navigator) {
+    return !!
+    /*@__PURE__*/
+    navigator.userAgent.match(pattern);
+  }
+}
+
+var IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
+var Edge = userAgent(/Edge/i);
+var FireFox = userAgent(/firefox/i);
+var Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
+var IOS = userAgent(/iP(ad|od|hone)/i);
+var ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);
+
+var captureMode = {
+  capture: false,
+  passive: false
+};
+
+function on(el, event, fn) {
+  el.addEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function off(el, event, fn) {
+  el.removeEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function matches(
+/**HTMLElement*/
+el,
+/**String*/
+selector) {
+  if (!selector) return;
+  selector[0] === '>' && (selector = selector.substring(1));
+
+  if (el) {
+    try {
+      if (el.matches) {
+        return el.matches(selector);
+      } else if (el.msMatchesSelector) {
+        return el.msMatchesSelector(selector);
+      } else if (el.webkitMatchesSelector) {
+        return el.webkitMatchesSelector(selector);
+      }
+    } catch (_) {
+      return false;
+    }
+  }
+
+  return false;
+}
+
+function getParentOrHost(el) {
+  return el.host && el !== document && el.host.nodeType ? el.host : el.parentNode;
+}
+
+function closest(
+/**HTMLElement*/
+el,
+/**String*/
+selector,
+/**HTMLElement*/
+ctx, includeCTX) {
+  if (el) {
+    ctx = ctx || document;
+
+    do {
+      if (selector != null && (selector[0] === '>' ? el.parentNode === ctx && matches(el, selector) : matches(el, selector)) || includeCTX && el === ctx) {
+        return el;
+      }
+
+      if (el === ctx) break;
+      /* jshint boss:true */
+    } while (el = getParentOrHost(el));
+  }
+
+  return null;
+}
+
+var R_SPACE = /\s+/g;
+
+function toggleClass(el, name, state) {
+  if (el && name) {
+    if (el.classList) {
+      el.classList[state ? 'add' : 'remove'](name);
+    } else {
+      var className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
+      el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
+    }
+  }
+}
+
+function css(el, prop, val) {
+  var style = el && el.style;
+
+  if (style) {
+    if (val === void 0) {
+      if (document.defaultView && document.defaultView.getComputedStyle) {
+        val = document.defaultView.getComputedStyle(el, '');
+      } else if (el.currentStyle) {
+        val = el.currentStyle;
+      }
+
+      return prop === void 0 ? val : val[prop];
+    } else {
+      if (!(prop in style) && prop.indexOf('webkit') === -1) {
+        prop = '-webkit-' + prop;
+      }
+
+      style[prop] = val + (typeof val === 'string' ? '' : 'px');
+    }
+  }
+}
+
+function matrix(el, selfOnly) {
+  var appliedTransforms = '';
+
+  if (typeof el === 'string') {
+    appliedTransforms = el;
+  } else {
+    do {
+      var transform = css(el, 'transform');
+
+      if (transform && transform !== 'none') {
+        appliedTransforms = transform + ' ' + appliedTransforms;
+      }
+      /* jshint boss:true */
+
+    } while (!selfOnly && (el = el.parentNode));
+  }
+
+  var matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
+  /*jshint -W056 */
+
+  return matrixFn && new matrixFn(appliedTransforms);
+}
+
+function find(ctx, tagName, iterator) {
+  if (ctx) {
+    var list = ctx.getElementsByTagName(tagName),
+        i = 0,
+        n = list.length;
+
+    if (iterator) {
+      for (; i < n; i++) {
+        iterator(list[i], i);
+      }
+    }
+
+    return list;
+  }
+
+  return [];
+}
+
+function getWindowScrollingElement() {
+  var scrollingElement = document.scrollingElement;
+
+  if (scrollingElement) {
+    return scrollingElement;
+  } else {
+    return document.documentElement;
+  }
+}
+/**
+ * Returns the "bounding client rect" of given element
+ * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
+ * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
+ * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
+ * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
+ * @param  {[HTMLElement]} container              The parent the element will be placed in
+ * @return {Object}                               The boundingClientRect of el, with specified adjustments
+ */
+
+
+function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
+  if (!el.getBoundingClientRect && el !== window) return;
+  var elRect, top, left, bottom, right, height, width;
+
+  if (el !== window && el !== getWindowScrollingElement()) {
+    elRect = el.getBoundingClientRect();
+    top = elRect.top;
+    left = elRect.left;
+    bottom = elRect.bottom;
+    right = elRect.right;
+    height = elRect.height;
+    width = elRect.width;
+  } else {
+    top = 0;
+    left = 0;
+    bottom = window.innerHeight;
+    right = window.innerWidth;
+    height = window.innerHeight;
+    width = window.innerWidth;
+  }
+
+  if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
+    // Adjust for translate()
+    container = container || el.parentNode; // solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
+    // Not needed on <= IE11
+
+    if (!IE11OrLess) {
+      do {
+        if (container && container.getBoundingClientRect && (css(container, 'transform') !== 'none' || relativeToNonStaticParent && css(container, 'position') !== 'static')) {
+          var containerRect = container.getBoundingClientRect(); // Set relative to edges of padding box of container
+
+          top -= containerRect.top + parseInt(css(container, 'border-top-width'));
+          left -= containerRect.left + parseInt(css(container, 'border-left-width'));
+          bottom = top + elRect.height;
+          right = left + elRect.width;
+          break;
+        }
+        /* jshint boss:true */
+
+      } while (container = container.parentNode);
+    }
+  }
+
+  if (undoScale && el !== window) {
+    // Adjust for scale()
+    var elMatrix = matrix(container || el),
+        scaleX = elMatrix && elMatrix.a,
+        scaleY = elMatrix && elMatrix.d;
+
+    if (elMatrix) {
+      top /= scaleY;
+      left /= scaleX;
+      width /= scaleX;
+      height /= scaleY;
+      bottom = top + height;
+      right = left + width;
+    }
+  }
+
+  return {
+    top: top,
+    left: left,
+    bottom: bottom,
+    right: right,
+    width: width,
+    height: height
+  };
+}
+/**
+ * Checks if a side of an element is scrolled past a side of its parents
+ * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
+ * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
+ * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
+ * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
+ */
+
+
+function isScrolledPast(el, elSide, parentSide) {
+  var parent = getParentAutoScrollElement(el, true),
+      elSideVal = getRect(el)[elSide];
+  /* jshint boss:true */
+
+  while (parent) {
+    var parentSideVal = getRect(parent)[parentSide],
+        visible = void 0;
+
+    if (parentSide === 'top' || parentSide === 'left') {
+      visible = elSideVal >= parentSideVal;
+    } else {
+      visible = elSideVal <= parentSideVal;
+    }
+
+    if (!visible) return parent;
+    if (parent === getWindowScrollingElement()) break;
+    parent = getParentAutoScrollElement(parent, false);
+  }
+
+  return false;
+}
+/**
+ * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
+ * and non-draggable elements
+ * @param  {HTMLElement} el       The parent element
+ * @param  {Number} childNum      The index of the child
+ * @param  {Object} options       Parent Sortable's options
+ * @return {HTMLElement}          The child at index childNum, or null if not found
+ */
+
+
+function getChild(el, childNum, options) {
+  var currentChild = 0,
+      i = 0,
+      children = el.children;
+
+  while (i < children.length) {
+    if (children[i].style.display !== 'none' && children[i] !== Sortable.ghost && children[i] !== Sortable.dragged && closest(children[i], options.draggable, el, false)) {
+      if (currentChild === childNum) {
+        return children[i];
+      }
+
+      currentChild++;
+    }
+
+    i++;
+  }
+
+  return null;
+}
+/**
+ * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
+ * @param  {HTMLElement} el       Parent element
+ * @param  {selector} selector    Any other elements that should be ignored
+ * @return {HTMLElement}          The last child, ignoring ghostEl
+ */
+
+
+function lastChild(el, selector) {
+  var last = el.lastElementChild;
+
+  while (last && (last === Sortable.ghost || css(last, 'display') === 'none' || selector && !matches(last, selector))) {
+    last = last.previousElementSibling;
+  }
+
+  return last || null;
+}
+/**
+ * Returns the index of an element within its parent for a selected set of
+ * elements
+ * @param  {HTMLElement} el
+ * @param  {selector} selector
+ * @return {number}
+ */
+
+
+function index(el, selector) {
+  var index = 0;
+
+  if (!el || !el.parentNode) {
+    return -1;
+  }
+  /* jshint boss:true */
+
+
+  while (el = el.previousElementSibling) {
+    if (el.nodeName.toUpperCase() !== 'TEMPLATE' && el !== Sortable.clone && (!selector || matches(el, selector))) {
+      index++;
+    }
+  }
+
+  return index;
+}
+/**
+ * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
+ * The value is returned in real pixels.
+ * @param  {HTMLElement} el
+ * @return {Array}             Offsets in the format of [left, top]
+ */
+
+
+function getRelativeScrollOffset(el) {
+  var offsetLeft = 0,
+      offsetTop = 0,
+      winScroller = getWindowScrollingElement();
+
+  if (el) {
+    do {
+      var elMatrix = matrix(el),
+          scaleX = elMatrix.a,
+          scaleY = elMatrix.d;
+      offsetLeft += el.scrollLeft * scaleX;
+      offsetTop += el.scrollTop * scaleY;
+    } while (el !== winScroller && (el = el.parentNode));
+  }
+
+  return [offsetLeft, offsetTop];
+}
+/**
+ * Returns the index of the object within the given array
+ * @param  {Array} arr   Array that may or may not hold the object
+ * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
+ * @return {Number}      The index of the object in the array, or -1
+ */
+
+
+function indexOfObject(arr, obj) {
+  for (var i in arr) {
+    if (!arr.hasOwnProperty(i)) continue;
+
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
+    }
+  }
+
+  return -1;
+}
+
+function getParentAutoScrollElement(el, includeSelf) {
+  // skip to window
+  if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
+  var elem = el;
+  var gotSelf = false;
+
+  do {
+    // we don't need to get elem css if it isn't even overflowing in the first place (performance)
+    if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
+      var elemCSS = css(elem);
+
+      if (elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') || elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')) {
+        if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
+        if (gotSelf || includeSelf) return elem;
+        gotSelf = true;
+      }
+    }
+    /* jshint boss:true */
+
+  } while (elem = elem.parentNode);
+
+  return getWindowScrollingElement();
+}
+
+function extend(dst, src) {
+  if (dst && src) {
+    for (var key in src) {
+      if (src.hasOwnProperty(key)) {
+        dst[key] = src[key];
+      }
+    }
+  }
+
+  return dst;
+}
+
+function isRectEqual(rect1, rect2) {
+  return Math.round(rect1.top) === Math.round(rect2.top) && Math.round(rect1.left) === Math.round(rect2.left) && Math.round(rect1.height) === Math.round(rect2.height) && Math.round(rect1.width) === Math.round(rect2.width);
+}
+
+var _throttleTimeout;
+
+function throttle(callback, ms) {
+  return function () {
+    if (!_throttleTimeout) {
+      var args = arguments,
+          _this = this;
+
+      if (args.length === 1) {
+        callback.call(_this, args[0]);
+      } else {
+        callback.apply(_this, args);
+      }
+
+      _throttleTimeout = setTimeout(function () {
+        _throttleTimeout = void 0;
+      }, ms);
+    }
+  };
+}
+
+function cancelThrottle() {
+  clearTimeout(_throttleTimeout);
+  _throttleTimeout = void 0;
+}
+
+function scrollBy(el, x, y) {
+  el.scrollLeft += x;
+  el.scrollTop += y;
+}
+
+function clone(el) {
+  var Polymer = window.Polymer;
+  var $ = window.jQuery || window.Zepto;
+
+  if (Polymer && Polymer.dom) {
+    return Polymer.dom(el).cloneNode(true);
+  } else if ($) {
+    return $(el).clone(true)[0];
+  } else {
+    return el.cloneNode(true);
+  }
+}
+
+function setRect(el, rect) {
+  css(el, 'position', 'absolute');
+  css(el, 'top', rect.top);
+  css(el, 'left', rect.left);
+  css(el, 'width', rect.width);
+  css(el, 'height', rect.height);
+}
+
+function unsetRect(el) {
+  css(el, 'position', '');
+  css(el, 'top', '');
+  css(el, 'left', '');
+  css(el, 'width', '');
+  css(el, 'height', '');
+}
+
+var expando = 'Sortable' + new Date().getTime();
+
+function AnimationStateManager() {
+  var animationStates = [],
+      animationCallbackId;
+  return {
+    captureAnimationState: function captureAnimationState() {
+      animationStates = [];
+      if (!this.options.animation) return;
+      var children = [].slice.call(this.el.children);
+      children.forEach(function (child) {
+        if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
+        animationStates.push({
+          target: child,
+          rect: getRect(child)
+        });
+
+        var fromRect = _objectSpread({}, animationStates[animationStates.length - 1].rect); // If animating: compensate for current animation
+
+
+        if (child.thisAnimationDuration) {
+          var childMatrix = matrix(child, true);
+
+          if (childMatrix) {
+            fromRect.top -= childMatrix.f;
+            fromRect.left -= childMatrix.e;
+          }
+        }
+
+        child.fromRect = fromRect;
+      });
+    },
+    addAnimationState: function addAnimationState(state) {
+      animationStates.push(state);
+    },
+    removeAnimationState: function removeAnimationState(target) {
+      animationStates.splice(indexOfObject(animationStates, {
+        target: target
+      }), 1);
+    },
+    animateAll: function animateAll(callback) {
+      var _this = this;
+
+      if (!this.options.animation) {
+        clearTimeout(animationCallbackId);
+        if (typeof callback === 'function') callback();
+        return;
+      }
+
+      var animating = false,
+          animationTime = 0;
+      animationStates.forEach(function (state) {
+        var time = 0,
+            target = state.target,
+            fromRect = target.fromRect,
+            toRect = getRect(target),
+            prevFromRect = target.prevFromRect,
+            prevToRect = target.prevToRect,
+            animatingRect = state.rect,
+            targetMatrix = matrix(target, true);
+
+        if (targetMatrix) {
+          // Compensate for current animation
+          toRect.top -= targetMatrix.f;
+          toRect.left -= targetMatrix.e;
+        }
+
+        target.toRect = toRect;
+
+        if (target.thisAnimationDuration) {
+          // Could also check if animatingRect is between fromRect and toRect
+          if (isRectEqual(prevFromRect, toRect) && !isRectEqual(fromRect, toRect) && // Make sure animatingRect is on line between toRect & fromRect
+          (animatingRect.top - toRect.top) / (animatingRect.left - toRect.left) === (fromRect.top - toRect.top) / (fromRect.left - toRect.left)) {
+            // If returning to same place as started from animation and on same axis
+            time = calculateRealTime(animatingRect, prevFromRect, prevToRect, _this.options);
+          }
+        } // if fromRect != toRect: animate
+
+
+        if (!isRectEqual(toRect, fromRect)) {
+          target.prevFromRect = fromRect;
+          target.prevToRect = toRect;
+
+          if (!time) {
+            time = _this.options.animation;
+          }
+
+          _this.animate(target, animatingRect, toRect, time);
+        }
+
+        if (time) {
+          animating = true;
+          animationTime = Math.max(animationTime, time);
+          clearTimeout(target.animationResetTimer);
+          target.animationResetTimer = setTimeout(function () {
+            target.animationTime = 0;
+            target.prevFromRect = null;
+            target.fromRect = null;
+            target.prevToRect = null;
+            target.thisAnimationDuration = null;
+          }, time);
+          target.thisAnimationDuration = time;
+        }
+      });
+      clearTimeout(animationCallbackId);
+
+      if (!animating) {
+        if (typeof callback === 'function') callback();
+      } else {
+        animationCallbackId = setTimeout(function () {
+          if (typeof callback === 'function') callback();
+        }, animationTime);
+      }
+
+      animationStates = [];
+    },
+    animate: function animate(target, currentRect, toRect, duration) {
+      if (duration) {
+        css(target, 'transition', '');
+        css(target, 'transform', '');
+        var elMatrix = matrix(this.el),
+            scaleX = elMatrix && elMatrix.a,
+            scaleY = elMatrix && elMatrix.d,
+            translateX = (currentRect.left - toRect.left) / (scaleX || 1),
+            translateY = (currentRect.top - toRect.top) / (scaleY || 1);
+        target.animatingX = !!translateX;
+        target.animatingY = !!translateY;
+        css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
+        repaint(target); // repaint
+
+        css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
+        css(target, 'transform', 'translate3d(0,0,0)');
+        typeof target.animated === 'number' && clearTimeout(target.animated);
+        target.animated = setTimeout(function () {
+          css(target, 'transition', '');
+          css(target, 'transform', '');
+          target.animated = false;
+          target.animatingX = false;
+          target.animatingY = false;
+        }, duration);
+      }
+    }
+  };
+}
+
+function repaint(target) {
+  return target.offsetWidth;
+}
+
+function calculateRealTime(animatingRect, fromRect, toRect, options) {
+  return Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) / Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2)) * options.animation;
+}
+
+var plugins = [];
+var defaults = {
+  initializeByDefault: true
+};
+var PluginManager = {
+  mount: function mount(plugin) {
+    // Set default static properties
+    for (var option in defaults) {
+      if (defaults.hasOwnProperty(option) && !(option in plugin)) {
+        plugin[option] = defaults[option];
+      }
+    }
+
+    plugins.push(plugin);
+  },
+  pluginEvent: function pluginEvent(eventName, sortable, evt) {
+    var _this = this;
+
+    this.eventCanceled = false;
+
+    evt.cancel = function () {
+      _this.eventCanceled = true;
+    };
+
+    var eventNameGlobal = eventName + 'Global';
+    plugins.forEach(function (plugin) {
+      if (!sortable[plugin.pluginName]) return; // Fire global events if it exists in this sortable
+
+      if (sortable[plugin.pluginName][eventNameGlobal]) {
+        sortable[plugin.pluginName][eventNameGlobal](_objectSpread({
+          sortable: sortable
+        }, evt));
+      } // Only fire plugin event if plugin is enabled in this sortable,
+      // and plugin has event defined
+
+
+      if (sortable.options[plugin.pluginName] && sortable[plugin.pluginName][eventName]) {
+        sortable[plugin.pluginName][eventName](_objectSpread({
+          sortable: sortable
+        }, evt));
+      }
+    });
+  },
+  initializePlugins: function initializePlugins(sortable, el, defaults, options) {
+    plugins.forEach(function (plugin) {
+      var pluginName = plugin.pluginName;
+      if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
+      var initialized = new plugin(sortable, el, sortable.options);
+      initialized.sortable = sortable;
+      initialized.options = sortable.options;
+      sortable[pluginName] = initialized; // Add default options from plugin
+
+      _extends(defaults, initialized.defaults);
+    });
+
+    for (var option in sortable.options) {
+      if (!sortable.options.hasOwnProperty(option)) continue;
+      var modified = this.modifyOption(sortable, option, sortable.options[option]);
+
+      if (typeof modified !== 'undefined') {
+        sortable.options[option] = modified;
+      }
+    }
+  },
+  getEventProperties: function getEventProperties(name, sortable) {
+    var eventProperties = {};
+    plugins.forEach(function (plugin) {
+      if (typeof plugin.eventProperties !== 'function') return;
+
+      _extends(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
+    });
+    return eventProperties;
+  },
+  modifyOption: function modifyOption(sortable, name, value) {
+    var modifiedValue;
+    plugins.forEach(function (plugin) {
+      // Plugin must exist on the Sortable
+      if (!sortable[plugin.pluginName]) return; // If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
+
+      if (plugin.optionListeners && typeof plugin.optionListeners[name] === 'function') {
+        modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
+      }
+    });
+    return modifiedValue;
+  }
+};
+
+function dispatchEvent(_ref) {
+  var sortable = _ref.sortable,
+      rootEl = _ref.rootEl,
+      name = _ref.name,
+      targetEl = _ref.targetEl,
+      cloneEl = _ref.cloneEl,
+      toEl = _ref.toEl,
+      fromEl = _ref.fromEl,
+      oldIndex = _ref.oldIndex,
+      newIndex = _ref.newIndex,
+      oldDraggableIndex = _ref.oldDraggableIndex,
+      newDraggableIndex = _ref.newDraggableIndex,
+      originalEvent = _ref.originalEvent,
+      putSortable = _ref.putSortable,
+      extraEventProperties = _ref.extraEventProperties;
+  sortable = sortable || rootEl && rootEl[expando];
+  if (!sortable) return;
+  var evt,
+      options = sortable.options,
+      onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1); // Support for new CustomEvent feature
+
+  if (window.CustomEvent && !IE11OrLess && !Edge) {
+    evt = new CustomEvent(name, {
+      bubbles: true,
+      cancelable: true
+    });
+  } else {
+    evt = document.createEvent('Event');
+    evt.initEvent(name, true, true);
+  }
+
+  evt.to = toEl || rootEl;
+  evt.from = fromEl || rootEl;
+  evt.item = targetEl || rootEl;
+  evt.clone = cloneEl;
+  evt.oldIndex = oldIndex;
+  evt.newIndex = newIndex;
+  evt.oldDraggableIndex = oldDraggableIndex;
+  evt.newDraggableIndex = newDraggableIndex;
+  evt.originalEvent = originalEvent;
+  evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
+
+  var allEventProperties = _objectSpread({}, extraEventProperties, PluginManager.getEventProperties(name, sortable));
+
+  for (var option in allEventProperties) {
+    evt[option] = allEventProperties[option];
+  }
+
+  if (rootEl) {
+    rootEl.dispatchEvent(evt);
+  }
+
+  if (options[onName]) {
+    options[onName].call(sortable, evt);
+  }
+}
+
+var pluginEvent = function pluginEvent(eventName, sortable) {
+  var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {},
+      originalEvent = _ref.evt,
+      data = _objectWithoutProperties(_ref, ["evt"]);
+
+  PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, _objectSpread({
+    dragEl: dragEl,
+    parentEl: parentEl,
+    ghostEl: ghostEl,
+    rootEl: rootEl,
+    nextEl: nextEl,
+    lastDownEl: lastDownEl,
+    cloneEl: cloneEl,
+    cloneHidden: cloneHidden,
+    dragStarted: moved,
+    putSortable: putSortable,
+    activeSortable: Sortable.active,
+    originalEvent: originalEvent,
+    oldIndex: oldIndex,
+    oldDraggableIndex: oldDraggableIndex,
+    newIndex: newIndex,
+    newDraggableIndex: newDraggableIndex,
+    hideGhostForTarget: _hideGhostForTarget,
+    unhideGhostForTarget: _unhideGhostForTarget,
+    cloneNowHidden: function cloneNowHidden() {
+      cloneHidden = true;
+    },
+    cloneNowShown: function cloneNowShown() {
+      cloneHidden = false;
+    },
+    dispatchSortableEvent: function dispatchSortableEvent(name) {
+      _dispatchEvent({
+        sortable: sortable,
+        name: name,
+        originalEvent: originalEvent
+      });
+    }
+  }, data));
+};
+
+function _dispatchEvent(info) {
+  dispatchEvent(_objectSpread({
+    putSortable: putSortable,
+    cloneEl: cloneEl,
+    targetEl: dragEl,
+    rootEl: rootEl,
+    oldIndex: oldIndex,
+    oldDraggableIndex: oldDraggableIndex,
+    newIndex: newIndex,
+    newDraggableIndex: newDraggableIndex
+  }, info));
+}
+
+var dragEl,
+    parentEl,
+    ghostEl,
+    rootEl,
+    nextEl,
+    lastDownEl,
+    cloneEl,
+    cloneHidden,
+    oldIndex,
+    newIndex,
+    oldDraggableIndex,
+    newDraggableIndex,
+    activeGroup,
+    putSortable,
+    awaitingDragStarted = false,
+    ignoreNextClick = false,
+    sortables = [],
+    tapEvt,
+    touchEvt,
+    lastDx,
+    lastDy,
+    tapDistanceLeft,
+    tapDistanceTop,
+    moved,
+    lastTarget,
+    lastDirection,
+    pastFirstInvertThresh = false,
+    isCircumstantialInvert = false,
+    targetMoveDistance,
+    // For positioning ghost absolutely
+ghostRelativeParent,
+    ghostRelativeParentInitialScroll = [],
+    // (left, top)
+_silent = false,
+    savedInputChecked = [];
+/** @const */
+
+var documentExists = typeof document !== 'undefined',
+    PositionGhostAbsolutely = IOS,
+    CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
+    // This will not pass for IE9, because IE9 DnD only works on anchors
+supportDraggable = documentExists && !ChromeForAndroid && !IOS && 'draggable' in document.createElement('div'),
+    supportCssPointerEvents = function () {
+  if (!documentExists) return; // false when <= IE11
+
+  if (IE11OrLess) {
+    return false;
+  }
+
+  var el = document.createElement('x');
+  el.style.cssText = 'pointer-events:auto';
+  return el.style.pointerEvents === 'auto';
+}(),
+    _detectDirection = function _detectDirection(el, options) {
+  var elCSS = css(el),
+      elWidth = parseInt(elCSS.width) - parseInt(elCSS.paddingLeft) - parseInt(elCSS.paddingRight) - parseInt(elCSS.borderLeftWidth) - parseInt(elCSS.borderRightWidth),
+      child1 = getChild(el, 0, options),
+      child2 = getChild(el, 1, options),
+      firstChildCSS = child1 && css(child1),
+      secondChildCSS = child2 && css(child2),
+      firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
+      secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
+
+  if (elCSS.display === 'flex') {
+    return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse' ? 'vertical' : 'horizontal';
+  }
+
+  if (elCSS.display === 'grid') {
+    return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
+  }
+
+  if (child1 && firstChildCSS["float"] && firstChildCSS["float"] !== 'none') {
+    var touchingSideChild2 = firstChildCSS["float"] === 'left' ? 'left' : 'right';
+    return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ? 'vertical' : 'horizontal';
+  }
+
+  return child1 && (firstChildCSS.display === 'block' || firstChildCSS.display === 'flex' || firstChildCSS.display === 'table' || firstChildCSS.display === 'grid' || firstChildWidth >= elWidth && elCSS[CSSFloatProperty] === 'none' || child2 && elCSS[CSSFloatProperty] === 'none' && firstChildWidth + secondChildWidth > elWidth) ? 'vertical' : 'horizontal';
+},
+    _dragElInRowColumn = function _dragElInRowColumn(dragRect, targetRect, vertical) {
+  var dragElS1Opp = vertical ? dragRect.left : dragRect.top,
+      dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
+      dragElOppLength = vertical ? dragRect.width : dragRect.height,
+      targetS1Opp = vertical ? targetRect.left : targetRect.top,
+      targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
+      targetOppLength = vertical ? targetRect.width : targetRect.height;
+  return dragElS1Opp === targetS1Opp || dragElS2Opp === targetS2Opp || dragElS1Opp + dragElOppLength / 2 === targetS1Opp + targetOppLength / 2;
+},
+
+/**
+ * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
+ * @param  {Number} x      X position
+ * @param  {Number} y      Y position
+ * @return {HTMLElement}   Element of the first found nearest Sortable
+ */
+_detectNearestEmptySortable = function _detectNearestEmptySortable(x, y) {
+  var ret;
+  sortables.some(function (sortable) {
+    if (lastChild(sortable)) return;
+    var rect = getRect(sortable),
+        threshold = sortable[expando].options.emptyInsertThreshold,
+        insideHorizontally = x >= rect.left - threshold && x <= rect.right + threshold,
+        insideVertically = y >= rect.top - threshold && y <= rect.bottom + threshold;
+
+    if (threshold && insideHorizontally && insideVertically) {
+      return ret = sortable;
+    }
+  });
+  return ret;
+},
+    _prepareGroup = function _prepareGroup(options) {
+  function toFn(value, pull) {
+    return function (to, from, dragEl, evt) {
+      var sameGroup = to.options.group.name && from.options.group.name && to.options.group.name === from.options.group.name;
+
+      if (value == null && (pull || sameGroup)) {
+        // Default pull value
+        // Default pull and put value if same group
+        return true;
+      } else if (value == null || value === false) {
+        return false;
+      } else if (pull && value === 'clone') {
+        return value;
+      } else if (typeof value === 'function') {
+        return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
+      } else {
+        var otherGroup = (pull ? to : from).options.group.name;
+        return value === true || typeof value === 'string' && value === otherGroup || value.join && value.indexOf(otherGroup) > -1;
+      }
+    };
+  }
+
+  var group = {};
+  var originalGroup = options.group;
+
+  if (!originalGroup || _typeof(originalGroup) != 'object') {
+    originalGroup = {
+      name: originalGroup
+    };
+  }
+
+  group.name = originalGroup.name;
+  group.checkPull = toFn(originalGroup.pull, true);
+  group.checkPut = toFn(originalGroup.put);
+  group.revertClone = originalGroup.revertClone;
+  options.group = group;
+},
+    _hideGhostForTarget = function _hideGhostForTarget() {
+  if (!supportCssPointerEvents && ghostEl) {
+    css(ghostEl, 'display', 'none');
+  }
+},
+    _unhideGhostForTarget = function _unhideGhostForTarget() {
+  if (!supportCssPointerEvents && ghostEl) {
+    css(ghostEl, 'display', '');
+  }
+}; // #1184 fix - Prevent click event on fallback if dragged but item not changed position
+
+
+if (documentExists) {
+  document.addEventListener('click', function (evt) {
+    if (ignoreNextClick) {
+      evt.preventDefault();
+      evt.stopPropagation && evt.stopPropagation();
+      evt.stopImmediatePropagation && evt.stopImmediatePropagation();
+      ignoreNextClick = false;
+      return false;
+    }
+  }, true);
+}
+
+var nearestEmptyInsertDetectEvent = function nearestEmptyInsertDetectEvent(evt) {
+  if (dragEl) {
+    evt = evt.touches ? evt.touches[0] : evt;
+
+    var nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
+
+    if (nearest) {
+      // Create imitation event
+      var event = {};
+
+      for (var i in evt) {
+        if (evt.hasOwnProperty(i)) {
+          event[i] = evt[i];
+        }
+      }
+
+      event.target = event.rootEl = nearest;
+      event.preventDefault = void 0;
+      event.stopPropagation = void 0;
+
+      nearest[expando]._onDragOver(event);
+    }
+  }
+};
+
+var _checkOutsideTargetEl = function _checkOutsideTargetEl(evt) {
+  if (dragEl) {
+    dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
+  }
+};
+/**
+ * @class  Sortable
+ * @param  {HTMLElement}  el
+ * @param  {Object}       [options]
+ */
+
+
+function Sortable(el, options) {
+  if (!(el && el.nodeType && el.nodeType === 1)) {
+    throw "Sortable: `el` must be an HTMLElement, not ".concat({}.toString.call(el));
+  }
+
+  this.el = el; // root element
+
+  this.options = options = _extends({}, options); // Export instance
+
+  el[expando] = this;
+  var defaults = {
+    group: null,
+    sort: true,
+    disabled: false,
+    store: null,
+    handle: null,
+    draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
+    swapThreshold: 1,
+    // percentage; 0 <= x <= 1
+    invertSwap: false,
+    // invert always
+    invertedSwapThreshold: null,
+    // will be set to same as swapThreshold if default
+    removeCloneOnHide: true,
+    direction: function direction() {
+      return _detectDirection(el, this.options);
+    },
+    ghostClass: 'sortable-ghost',
+    chosenClass: 'sortable-chosen',
+    dragClass: 'sortable-drag',
+    ignore: 'a, img',
+    filter: null,
+    preventOnFilter: true,
+    animation: 0,
+    easing: null,
+    setData: function setData(dataTransfer, dragEl) {
+      dataTransfer.setData('Text', dragEl.textContent);
+    },
+    dropBubble: false,
+    dragoverBubble: false,
+    dataIdAttr: 'data-id',
+    delay: 0,
+    delayOnTouchOnly: false,
+    touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
+    forceFallback: false,
+    fallbackClass: 'sortable-fallback',
+    fallbackOnBody: false,
+    fallbackTolerance: 0,
+    fallbackOffset: {
+      x: 0,
+      y: 0
+    },
+    supportPointer: Sortable.supportPointer !== false && 'PointerEvent' in window,
+    emptyInsertThreshold: 5
+  };
+  PluginManager.initializePlugins(this, el, defaults); // Set default options
+
+  for (var name in defaults) {
+    !(name in options) && (options[name] = defaults[name]);
+  }
+
+  _prepareGroup(options); // Bind all private methods
+
+
+  for (var fn in this) {
+    if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+      this[fn] = this[fn].bind(this);
+    }
+  } // Setup drag mode
+
+
+  this.nativeDraggable = options.forceFallback ? false : supportDraggable;
+
+  if (this.nativeDraggable) {
+    // Touch start threshold cannot be greater than the native dragstart threshold
+    this.options.touchStartThreshold = 1;
+  } // Bind events
+
+
+  if (options.supportPointer) {
+    on(el, 'pointerdown', this._onTapStart);
+  } else {
+    on(el, 'mousedown', this._onTapStart);
+    on(el, 'touchstart', this._onTapStart);
+  }
+
+  if (this.nativeDraggable) {
+    on(el, 'dragover', this);
+    on(el, 'dragenter', this);
+  }
+
+  sortables.push(this.el); // Restore sorting
+
+  options.store && options.store.get && this.sort(options.store.get(this) || []); // Add animation state manager
+
+  _extends(this, AnimationStateManager());
+}
+
+Sortable.prototype =
+/** @lends Sortable.prototype */
+{
+  constructor: Sortable,
+  _isOutsideThisEl: function _isOutsideThisEl(target) {
+    if (!this.el.contains(target) && target !== this.el) {
+      lastTarget = null;
+    }
+  },
+  _getDirection: function _getDirection(evt, target) {
+    return typeof this.options.direction === 'function' ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
+  },
+  _onTapStart: function _onTapStart(
+  /** Event|TouchEvent */
+  evt) {
+    if (!evt.cancelable) return;
+
+    var _this = this,
+        el = this.el,
+        options = this.options,
+        preventOnFilter = options.preventOnFilter,
+        type = evt.type,
+        touch = evt.touches && evt.touches[0] || evt.pointerType && evt.pointerType === 'touch' && evt,
+        target = (touch || evt).target,
+        originalTarget = evt.target.shadowRoot && (evt.path && evt.path[0] || evt.composedPath && evt.composedPath()[0]) || target,
+        filter = options.filter;
+
+    _saveInputCheckedState(el); // Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
+
+
+    if (dragEl) {
+      return;
+    }
+
+    if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
+      return; // only left button and enabled
+    } // cancel dnd if original target is content editable
+
+
+    if (originalTarget.isContentEditable) {
+      return;
+    }
+
+    target = closest(target, options.draggable, el, false);
+
+    if (target && target.animated) {
+      return;
+    }
+
+    if (lastDownEl === target) {
+      // Ignoring duplicate `down`
+      return;
+    } // Get the index of the dragged element within its parent
+
+
+    oldIndex = index(target);
+    oldDraggableIndex = index(target, options.draggable); // Check filter
+
+    if (typeof filter === 'function') {
+      if (filter.call(this, evt, target, this)) {
+        _dispatchEvent({
+          sortable: _this,
+          rootEl: originalTarget,
+          name: 'filter',
+          targetEl: target,
+          toEl: el,
+          fromEl: el
+        });
+
+        pluginEvent('filter', _this, {
+          evt: evt
+        });
+        preventOnFilter && evt.cancelable && evt.preventDefault();
+        return; // cancel dnd
+      }
+    } else if (filter) {
+      filter = filter.split(',').some(function (criteria) {
+        criteria = closest(originalTarget, criteria.trim(), el, false);
+
+        if (criteria) {
+          _dispatchEvent({
+            sortable: _this,
+            rootEl: criteria,
+            name: 'filter',
+            targetEl: target,
+            fromEl: el,
+            toEl: el
+          });
+
+          pluginEvent('filter', _this, {
+            evt: evt
+          });
+          return true;
+        }
+      });
+
+      if (filter) {
+        preventOnFilter && evt.cancelable && evt.preventDefault();
+        return; // cancel dnd
+      }
+    }
+
+    if (options.handle && !closest(originalTarget, options.handle, el, false)) {
+      return;
+    } // Prepare `dragstart`
+
+
+    this._prepareDragStart(evt, touch, target);
+  },
+  _prepareDragStart: function _prepareDragStart(
+  /** Event */
+  evt,
+  /** Touch */
+  touch,
+  /** HTMLElement */
+  target) {
+    var _this = this,
+        el = _this.el,
+        options = _this.options,
+        ownerDocument = el.ownerDocument,
+        dragStartFn;
+
+    if (target && !dragEl && target.parentNode === el) {
+      var dragRect = getRect(target);
+      rootEl = el;
+      dragEl = target;
+      parentEl = dragEl.parentNode;
+      nextEl = dragEl.nextSibling;
+      lastDownEl = target;
+      activeGroup = options.group;
+      Sortable.dragged = dragEl;
+      tapEvt = {
+        target: dragEl,
+        clientX: (touch || evt).clientX,
+        clientY: (touch || evt).clientY
+      };
+      tapDistanceLeft = tapEvt.clientX - dragRect.left;
+      tapDistanceTop = tapEvt.clientY - dragRect.top;
+      this._lastX = (touch || evt).clientX;
+      this._lastY = (touch || evt).clientY;
+      dragEl.style['will-change'] = 'all';
+
+      dragStartFn = function dragStartFn() {
+        pluginEvent('delayEnded', _this, {
+          evt: evt
+        });
+
+        if (Sortable.eventCanceled) {
+          _this._onDrop();
+
+          return;
+        } // Delayed drag has been triggered
+        // we can re-enable the events: touchmove/mousemove
+
+
+        _this._disableDelayedDragEvents();
+
+        if (!FireFox && _this.nativeDraggable) {
+          dragEl.draggable = true;
+        } // Bind the events: dragstart/dragend
+
+
+        _this._triggerDragStart(evt, touch); // Drag start event
+
+
+        _dispatchEvent({
+          sortable: _this,
+          name: 'choose',
+          originalEvent: evt
+        }); // Chosen item
+
+
+        toggleClass(dragEl, options.chosenClass, true);
+      }; // Disable "draggable"
+
+
+      options.ignore.split(',').forEach(function (criteria) {
+        find(dragEl, criteria.trim(), _disableDraggable);
+      });
+      on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
+      on(ownerDocument, 'mouseup', _this._onDrop);
+      on(ownerDocument, 'touchend', _this._onDrop);
+      on(ownerDocument, 'touchcancel', _this._onDrop); // Make dragEl draggable (must be before delay for FireFox)
+
+      if (FireFox && this.nativeDraggable) {
+        this.options.touchStartThreshold = 4;
+        dragEl.draggable = true;
+      }
+
+      pluginEvent('delayStart', this, {
+        evt: evt
+      }); // Delay is impossible for native DnD in Edge or IE
+
+      if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
+        if (Sortable.eventCanceled) {
+          this._onDrop();
+
+          return;
+        } // If the user moves the pointer or let go the click or touch
+        // before the delay has been reached:
+        // disable the delayed drag
+
+
+        on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
+        on(ownerDocument, 'touchend', _this._disableDelayedDrag);
+        on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
+        on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
+        on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
+        options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
+        _this._dragStartTimer = setTimeout(dragStartFn, options.delay);
+      } else {
+        dragStartFn();
+      }
+    }
+  },
+  _delayedDragTouchMoveHandler: function _delayedDragTouchMoveHandler(
+  /** TouchEvent|PointerEvent **/
+  e) {
+    var touch = e.touches ? e.touches[0] : e;
+
+    if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) >= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))) {
+      this._disableDelayedDrag();
+    }
+  },
+  _disableDelayedDrag: function _disableDelayedDrag() {
+    dragEl && _disableDraggable(dragEl);
+    clearTimeout(this._dragStartTimer);
+
+    this._disableDelayedDragEvents();
+  },
+  _disableDelayedDragEvents: function _disableDelayedDragEvents() {
+    var ownerDocument = this.el.ownerDocument;
+    off(ownerDocument, 'mouseup', this._disableDelayedDrag);
+    off(ownerDocument, 'touchend', this._disableDelayedDrag);
+    off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
+    off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
+    off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
+    off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
+  },
+  _triggerDragStart: function _triggerDragStart(
+  /** Event */
+  evt,
+  /** Touch */
+  touch) {
+    touch = touch || evt.pointerType == 'touch' && evt;
+
+    if (!this.nativeDraggable || touch) {
+      if (this.options.supportPointer) {
+        on(document, 'pointermove', this._onTouchMove);
+      } else if (touch) {
+        on(document, 'touchmove', this._onTouchMove);
+      } else {
+        on(document, 'mousemove', this._onTouchMove);
+      }
+    } else {
+      on(dragEl, 'dragend', this);
+      on(rootEl, 'dragstart', this._onDragStart);
+    }
+
+    try {
+      if (document.selection) {
+        // Timeout neccessary for IE9
+        _nextTick(function () {
+          document.selection.empty();
+        });
+      } else {
+        window.getSelection().removeAllRanges();
+      }
+    } catch (err) {}
+  },
+  _dragStarted: function _dragStarted(fallback, evt) {
+
+    awaitingDragStarted = false;
+
+    if (rootEl && dragEl) {
+      pluginEvent('dragStarted', this, {
+        evt: evt
+      });
+
+      if (this.nativeDraggable) {
+        on(document, 'dragover', _checkOutsideTargetEl);
+      }
+
+      var options = this.options; // Apply effect
+
+      !fallback && toggleClass(dragEl, options.dragClass, false);
+      toggleClass(dragEl, options.ghostClass, true);
+      Sortable.active = this;
+      fallback && this._appendGhost(); // Drag start event
+
+      _dispatchEvent({
+        sortable: this,
+        name: 'start',
+        originalEvent: evt
+      });
+    } else {
+      this._nulling();
+    }
+  },
+  _emulateDragOver: function _emulateDragOver() {
+    if (touchEvt) {
+      this._lastX = touchEvt.clientX;
+      this._lastY = touchEvt.clientY;
+
+      _hideGhostForTarget();
+
+      var target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+      var parent = target;
+
+      while (target && target.shadowRoot) {
+        target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+        if (target === parent) break;
+        parent = target;
+      }
+
+      dragEl.parentNode[expando]._isOutsideThisEl(target);
+
+      if (parent) {
+        do {
+          if (parent[expando]) {
+            var inserted = void 0;
+            inserted = parent[expando]._onDragOver({
+              clientX: touchEvt.clientX,
+              clientY: touchEvt.clientY,
+              target: target,
+              rootEl: parent
+            });
+
+            if (inserted && !this.options.dragoverBubble) {
+              break;
+            }
+          }
+
+          target = parent; // store last element
+        }
+        /* jshint boss:true */
+        while (parent = parent.parentNode);
+      }
+
+      _unhideGhostForTarget();
+    }
+  },
+  _onTouchMove: function _onTouchMove(
+  /**TouchEvent*/
+  evt) {
+    if (tapEvt) {
+      var options = this.options,
+          fallbackTolerance = options.fallbackTolerance,
+          fallbackOffset = options.fallbackOffset,
+          touch = evt.touches ? evt.touches[0] : evt,
+          ghostMatrix = ghostEl && matrix(ghostEl, true),
+          scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
+          scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
+          relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
+          dx = (touch.clientX - tapEvt.clientX + fallbackOffset.x) / (scaleX || 1) + (relativeScrollOffset ? relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0] : 0) / (scaleX || 1),
+          dy = (touch.clientY - tapEvt.clientY + fallbackOffset.y) / (scaleY || 1) + (relativeScrollOffset ? relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1] : 0) / (scaleY || 1); // only set the status to dragging, when we are actually dragging
+
+      if (!Sortable.active && !awaitingDragStarted) {
+        if (fallbackTolerance && Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance) {
+          return;
+        }
+
+        this._onDragStart(evt, true);
+      }
+
+      if (ghostEl) {
+        if (ghostMatrix) {
+          ghostMatrix.e += dx - (lastDx || 0);
+          ghostMatrix.f += dy - (lastDy || 0);
+        } else {
+          ghostMatrix = {
+            a: 1,
+            b: 0,
+            c: 0,
+            d: 1,
+            e: dx,
+            f: dy
+          };
+        }
+
+        var cssMatrix = "matrix(".concat(ghostMatrix.a, ",").concat(ghostMatrix.b, ",").concat(ghostMatrix.c, ",").concat(ghostMatrix.d, ",").concat(ghostMatrix.e, ",").concat(ghostMatrix.f, ")");
+        css(ghostEl, 'webkitTransform', cssMatrix);
+        css(ghostEl, 'mozTransform', cssMatrix);
+        css(ghostEl, 'msTransform', cssMatrix);
+        css(ghostEl, 'transform', cssMatrix);
+        lastDx = dx;
+        lastDy = dy;
+        touchEvt = touch;
+      }
+
+      evt.cancelable && evt.preventDefault();
+    }
+  },
+  _appendGhost: function _appendGhost() {
+    // Bug if using scale(): https://stackoverflow.com/questions/2637058
+    // Not being adjusted for
+    if (!ghostEl) {
+      var container = this.options.fallbackOnBody ? document.body : rootEl,
+          rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
+          options = this.options; // Position absolutely
+
+      if (PositionGhostAbsolutely) {
+        // Get relatively positioned parent
+        ghostRelativeParent = container;
+
+        while (css(ghostRelativeParent, 'position') === 'static' && css(ghostRelativeParent, 'transform') === 'none' && ghostRelativeParent !== document) {
+          ghostRelativeParent = ghostRelativeParent.parentNode;
+        }
+
+        if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
+          if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
+          rect.top += ghostRelativeParent.scrollTop;
+          rect.left += ghostRelativeParent.scrollLeft;
+        } else {
+          ghostRelativeParent = getWindowScrollingElement();
+        }
+
+        ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
+      }
+
+      ghostEl = dragEl.cloneNode(true);
+      toggleClass(ghostEl, options.ghostClass, false);
+      toggleClass(ghostEl, options.fallbackClass, true);
+      toggleClass(ghostEl, options.dragClass, true);
+      css(ghostEl, 'transition', '');
+      css(ghostEl, 'transform', '');
+      css(ghostEl, 'box-sizing', 'border-box');
+      css(ghostEl, 'margin', 0);
+      css(ghostEl, 'top', rect.top);
+      css(ghostEl, 'left', rect.left);
+      css(ghostEl, 'width', rect.width);
+      css(ghostEl, 'height', rect.height);
+      css(ghostEl, 'opacity', '0.8');
+      css(ghostEl, 'position', PositionGhostAbsolutely ? 'absolute' : 'fixed');
+      css(ghostEl, 'zIndex', '100000');
+      css(ghostEl, 'pointerEvents', 'none');
+      Sortable.ghost = ghostEl;
+      container.appendChild(ghostEl); // Set transform-origin
+
+      css(ghostEl, 'transform-origin', tapDistanceLeft / parseInt(ghostEl.style.width) * 100 + '% ' + tapDistanceTop / parseInt(ghostEl.style.height) * 100 + '%');
+    }
+  },
+  _onDragStart: function _onDragStart(
+  /**Event*/
+  evt,
+  /**boolean*/
+  fallback) {
+    var _this = this;
+
+    var dataTransfer = evt.dataTransfer;
+    var options = _this.options;
+    pluginEvent('dragStart', this, {
+      evt: evt
+    });
+
+    if (Sortable.eventCanceled) {
+      this._onDrop();
+
+      return;
+    }
+
+    pluginEvent('setupClone', this);
+
+    if (!Sortable.eventCanceled) {
+      cloneEl = clone(dragEl);
+      cloneEl.draggable = false;
+      cloneEl.style['will-change'] = '';
+
+      this._hideClone();
+
+      toggleClass(cloneEl, this.options.chosenClass, false);
+      Sortable.clone = cloneEl;
+    } // #1143: IFrame support workaround
+
+
+    _this.cloneId = _nextTick(function () {
+      pluginEvent('clone', _this);
+      if (Sortable.eventCanceled) return;
+
+      if (!_this.options.removeCloneOnHide) {
+        rootEl.insertBefore(cloneEl, dragEl);
+      }
+
+      _this._hideClone();
+
+      _dispatchEvent({
+        sortable: _this,
+        name: 'clone'
+      });
+    });
+    !fallback && toggleClass(dragEl, options.dragClass, true); // Set proper drop events
+
+    if (fallback) {
+      ignoreNextClick = true;
+      _this._loopId = setInterval(_this._emulateDragOver, 50);
+    } else {
+      // Undo what was set in _prepareDragStart before drag started
+      off(document, 'mouseup', _this._onDrop);
+      off(document, 'touchend', _this._onDrop);
+      off(document, 'touchcancel', _this._onDrop);
+
+      if (dataTransfer) {
+        dataTransfer.effectAllowed = 'move';
+        options.setData && options.setData.call(_this, dataTransfer, dragEl);
+      }
+
+      on(document, 'drop', _this); // #1276 fix:
+
+      css(dragEl, 'transform', 'translateZ(0)');
+    }
+
+    awaitingDragStarted = true;
+    _this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
+    on(document, 'selectstart', _this);
+    moved = true;
+
+    if (Safari) {
+      css(document.body, 'user-select', 'none');
+    }
+  },
+  // Returns true - if no further action is needed (either inserted or another condition)
+  _onDragOver: function _onDragOver(
+  /**Event*/
+  evt) {
+    var el = this.el,
+        target = evt.target,
+        dragRect,
+        targetRect,
+        revert,
+        options = this.options,
+        group = options.group,
+        activeSortable = Sortable.active,
+        isOwner = activeGroup === group,
+        canSort = options.sort,
+        fromSortable = putSortable || activeSortable,
+        vertical,
+        _this = this,
+        completedFired = false;
+
+    if (_silent) return;
+
+    function dragOverEvent(name, extra) {
+      pluginEvent(name, _this, _objectSpread({
+        evt: evt,
+        isOwner: isOwner,
+        axis: vertical ? 'vertical' : 'horizontal',
+        revert: revert,
+        dragRect: dragRect,
+        targetRect: targetRect,
+        canSort: canSort,
+        fromSortable: fromSortable,
+        target: target,
+        completed: completed,
+        onMove: function onMove(target, after) {
+          return _onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
+        },
+        changed: changed
+      }, extra));
+    } // Capture animation state
+
+
+    function capture() {
+      dragOverEvent('dragOverAnimationCapture');
+
+      _this.captureAnimationState();
+
+      if (_this !== fromSortable) {
+        fromSortable.captureAnimationState();
+      }
+    } // Return invocation when dragEl is inserted (or completed)
+
+
+    function completed(insertion) {
+      dragOverEvent('dragOverCompleted', {
+        insertion: insertion
+      });
+
+      if (insertion) {
+        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+        if (isOwner) {
+          activeSortable._hideClone();
+        } else {
+          activeSortable._showClone(_this);
+        }
+
+        if (_this !== fromSortable) {
+          // Set ghost class to new sortable's ghost class
+          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
+          toggleClass(dragEl, options.ghostClass, true);
+        }
+
+        if (putSortable !== _this && _this !== Sortable.active) {
+          putSortable = _this;
+        } else if (_this === Sortable.active && putSortable) {
+          putSortable = null;
+        } // Animation
+
+
+        if (fromSortable === _this) {
+          _this._ignoreWhileAnimating = target;
+        }
+
+        _this.animateAll(function () {
+          dragOverEvent('dragOverAnimationComplete');
+          _this._ignoreWhileAnimating = null;
+        });
+
+        if (_this !== fromSortable) {
+          fromSortable.animateAll();
+          fromSortable._ignoreWhileAnimating = null;
+        }
+      } // Null lastTarget if it is not inside a previously swapped element
+
+
+      if (target === dragEl && !dragEl.animated || target === el && !target.animated) {
+        lastTarget = null;
+      } // no bubbling and not fallback
+
+
+      if (!options.dragoverBubble && !evt.rootEl && target !== document) {
+        dragEl.parentNode[expando]._isOutsideThisEl(evt.target); // Do not detect for empty insert if already inserted
+
+
+        !insertion && nearestEmptyInsertDetectEvent(evt);
+      }
+
+      !options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
+      return completedFired = true;
+    } // Call when dragEl has been inserted
+
+
+    function changed() {
+      newIndex = index(dragEl);
+      newDraggableIndex = index(dragEl, options.draggable);
+
+      _dispatchEvent({
+        sortable: _this,
+        name: 'change',
+        toEl: el,
+        newIndex: newIndex,
+        newDraggableIndex: newDraggableIndex,
+        originalEvent: evt
+      });
+    }
+
+    if (evt.preventDefault !== void 0) {
+      evt.cancelable && evt.preventDefault();
+    }
+
+    target = closest(target, options.draggable, el, true);
+    dragOverEvent('dragOver');
+    if (Sortable.eventCanceled) return completedFired;
+
+    if (dragEl.contains(evt.target) || target.animated && target.animatingX && target.animatingY || _this._ignoreWhileAnimating === target) {
+      return completed(false);
+    }
+
+    ignoreNextClick = false;
+
+    if (activeSortable && !options.disabled && (isOwner ? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
+    : putSortable === this || (this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) && group.checkPut(this, activeSortable, dragEl, evt))) {
+      vertical = this._getDirection(evt, target) === 'vertical';
+      dragRect = getRect(dragEl);
+      dragOverEvent('dragOverValid');
+      if (Sortable.eventCanceled) return completedFired;
+
+      if (revert) {
+        parentEl = rootEl; // actualization
+
+        capture();
+
+        this._hideClone();
+
+        dragOverEvent('revert');
+
+        if (!Sortable.eventCanceled) {
+          if (nextEl) {
+            rootEl.insertBefore(dragEl, nextEl);
+          } else {
+            rootEl.appendChild(dragEl);
+          }
+        }
+
+        return completed(true);
+      }
+
+      var elLastChild = lastChild(el, options.draggable);
+
+      if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
+        // If already at end of list: Do not insert
+        if (elLastChild === dragEl) {
+          return completed(false);
+        } // assign target only if condition is true
+
+
+        if (elLastChild && el === evt.target) {
+          target = elLastChild;
+        }
+
+        if (target) {
+          targetRect = getRect(target);
+        }
+
+        if (_onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
+          capture();
+          el.appendChild(dragEl);
+          parentEl = el; // actualization
+
+          changed();
+          return completed(true);
+        }
+      } else if (target.parentNode === el) {
+        targetRect = getRect(target);
+        var direction = 0,
+            targetBeforeFirstSwap,
+            differentLevel = dragEl.parentNode !== el,
+            differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
+            side1 = vertical ? 'top' : 'left',
+            scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
+            scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
+
+        if (lastTarget !== target) {
+          targetBeforeFirstSwap = targetRect[side1];
+          pastFirstInvertThresh = false;
+          isCircumstantialInvert = !differentRowCol && options.invertSwap || differentLevel;
+        }
+
+        direction = _getSwapDirection(evt, target, targetRect, vertical, differentRowCol ? 1 : options.swapThreshold, options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold, isCircumstantialInvert, lastTarget === target);
+        var sibling;
+
+        if (direction !== 0) {
+          // Check if target is beside dragEl in respective direction (ignoring hidden elements)
+          var dragIndex = index(dragEl);
+
+          do {
+            dragIndex -= direction;
+            sibling = parentEl.children[dragIndex];
+          } while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
+        } // If dragEl is already beside target: Do not insert
+
+
+        if (direction === 0 || sibling === target) {
+          return completed(false);
+        }
+
+        lastTarget = target;
+        lastDirection = direction;
+        var nextSibling = target.nextElementSibling,
+            after = false;
+        after = direction === 1;
+
+        var moveVector = _onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
+
+        if (moveVector !== false) {
+          if (moveVector === 1 || moveVector === -1) {
+            after = moveVector === 1;
+          }
+
+          _silent = true;
+          setTimeout(_unsilent, 30);
+          capture();
+
+          if (after && !nextSibling) {
+            el.appendChild(dragEl);
+          } else {
+            target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
+          } // Undo chrome's scroll adjustment (has no effect on other browsers)
+
+
+          if (scrolledPastTop) {
+            scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
+          }
+
+          parentEl = dragEl.parentNode; // actualization
+          // must be done before animation
+
+          if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
+            targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
+          }
+
+          changed();
+          return completed(true);
+        }
+      }
+
+      if (el.contains(dragEl)) {
+        return completed(false);
+      }
+    }
+
+    return false;
+  },
+  _ignoreWhileAnimating: null,
+  _offMoveEvents: function _offMoveEvents() {
+    off(document, 'mousemove', this._onTouchMove);
+    off(document, 'touchmove', this._onTouchMove);
+    off(document, 'pointermove', this._onTouchMove);
+    off(document, 'dragover', nearestEmptyInsertDetectEvent);
+    off(document, 'mousemove', nearestEmptyInsertDetectEvent);
+    off(document, 'touchmove', nearestEmptyInsertDetectEvent);
+  },
+  _offUpEvents: function _offUpEvents() {
+    var ownerDocument = this.el.ownerDocument;
+    off(ownerDocument, 'mouseup', this._onDrop);
+    off(ownerDocument, 'touchend', this._onDrop);
+    off(ownerDocument, 'pointerup', this._onDrop);
+    off(ownerDocument, 'touchcancel', this._onDrop);
+    off(document, 'selectstart', this);
+  },
+  _onDrop: function _onDrop(
+  /**Event*/
+  evt) {
+    var el = this.el,
+        options = this.options; // Get the index of the dragged element within its parent
+
+    newIndex = index(dragEl);
+    newDraggableIndex = index(dragEl, options.draggable);
+    pluginEvent('drop', this, {
+      evt: evt
+    });
+    parentEl = dragEl && dragEl.parentNode; // Get again after plugin event
+
+    newIndex = index(dragEl);
+    newDraggableIndex = index(dragEl, options.draggable);
+
+    if (Sortable.eventCanceled) {
+      this._nulling();
+
+      return;
+    }
+
+    awaitingDragStarted = false;
+    isCircumstantialInvert = false;
+    pastFirstInvertThresh = false;
+    clearInterval(this._loopId);
+    clearTimeout(this._dragStartTimer);
+
+    _cancelNextTick(this.cloneId);
+
+    _cancelNextTick(this._dragStartId); // Unbind events
+
+
+    if (this.nativeDraggable) {
+      off(document, 'drop', this);
+      off(el, 'dragstart', this._onDragStart);
+    }
+
+    this._offMoveEvents();
+
+    this._offUpEvents();
+
+    if (Safari) {
+      css(document.body, 'user-select', '');
+    }
+
+    css(dragEl, 'transform', '');
+
+    if (evt) {
+      if (moved) {
+        evt.cancelable && evt.preventDefault();
+        !options.dropBubble && evt.stopPropagation();
+      }
+
+      ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
+
+      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+        // Remove clone(s)
+        cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
+      }
+
+      if (dragEl) {
+        if (this.nativeDraggable) {
+          off(dragEl, 'dragend', this);
+        }
+
+        _disableDraggable(dragEl);
+
+        dragEl.style['will-change'] = ''; // Remove classes
+        // ghostClass is added in dragStarted
+
+        if (moved && !awaitingDragStarted) {
+          toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
+        }
+
+        toggleClass(dragEl, this.options.chosenClass, false); // Drag stop event
+
+        _dispatchEvent({
+          sortable: this,
+          name: 'unchoose',
+          toEl: parentEl,
+          newIndex: null,
+          newDraggableIndex: null,
+          originalEvent: evt
+        });
+
+        if (rootEl !== parentEl) {
+          if (newIndex >= 0) {
+            // Add event
+            _dispatchEvent({
+              rootEl: parentEl,
+              name: 'add',
+              toEl: parentEl,
+              fromEl: rootEl,
+              originalEvent: evt
+            }); // Remove event
+
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'remove',
+              toEl: parentEl,
+              originalEvent: evt
+            }); // drag from one list and drop into another
+
+
+            _dispatchEvent({
+              rootEl: parentEl,
+              name: 'sort',
+              toEl: parentEl,
+              fromEl: rootEl,
+              originalEvent: evt
+            });
+
+            _dispatchEvent({
+              sortable: this,
+              name: 'sort',
+              toEl: parentEl,
+              originalEvent: evt
+            });
+          }
+
+          putSortable && putSortable.save();
+        } else {
+          if (newIndex !== oldIndex) {
+            if (newIndex >= 0) {
+              // drag & drop within the same list
+              _dispatchEvent({
+                sortable: this,
+                name: 'update',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+
+              _dispatchEvent({
+                sortable: this,
+                name: 'sort',
+                toEl: parentEl,
+                originalEvent: evt
+              });
+            }
+          }
+        }
+
+        if (Sortable.active) {
+          /* jshint eqnull:true */
+          if (newIndex == null || newIndex === -1) {
+            newIndex = oldIndex;
+            newDraggableIndex = oldDraggableIndex;
+          }
+
+          _dispatchEvent({
+            sortable: this,
+            name: 'end',
+            toEl: parentEl,
+            originalEvent: evt
+          }); // Save sorting
+
+
+          this.save();
+        }
+      }
+    }
+
+    this._nulling();
+  },
+  _nulling: function _nulling() {
+    pluginEvent('nulling', this);
+    rootEl = dragEl = parentEl = ghostEl = nextEl = cloneEl = lastDownEl = cloneHidden = tapEvt = touchEvt = moved = newIndex = newDraggableIndex = oldIndex = oldDraggableIndex = lastTarget = lastDirection = putSortable = activeGroup = Sortable.dragged = Sortable.ghost = Sortable.clone = Sortable.active = null;
+    savedInputChecked.forEach(function (el) {
+      el.checked = true;
+    });
+    savedInputChecked.length = lastDx = lastDy = 0;
+  },
+  handleEvent: function handleEvent(
+  /**Event*/
+  evt) {
+    switch (evt.type) {
+      case 'drop':
+      case 'dragend':
+        this._onDrop(evt);
+
+        break;
+
+      case 'dragenter':
+      case 'dragover':
+        if (dragEl) {
+          this._onDragOver(evt);
+
+          _globalDragOver(evt);
+        }
+
+        break;
+
+      case 'selectstart':
+        evt.preventDefault();
+        break;
+    }
+  },
+
+  /**
+   * Serializes the item into an array of string.
+   * @returns {String[]}
+   */
+  toArray: function toArray() {
+    var order = [],
+        el,
+        children = this.el.children,
+        i = 0,
+        n = children.length,
+        options = this.options;
+
+    for (; i < n; i++) {
+      el = children[i];
+
+      if (closest(el, options.draggable, this.el, false)) {
+        order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
+      }
+    }
+
+    return order;
+  },
+
+  /**
+   * Sorts the elements according to the array.
+   * @param  {String[]}  order  order of the items
+   */
+  sort: function sort(order) {
+    var items = {},
+        rootEl = this.el;
+    this.toArray().forEach(function (id, i) {
+      var el = rootEl.children[i];
+
+      if (closest(el, this.options.draggable, rootEl, false)) {
+        items[id] = el;
+      }
+    }, this);
+    order.forEach(function (id) {
+      if (items[id]) {
+        rootEl.removeChild(items[id]);
+        rootEl.appendChild(items[id]);
+      }
+    });
+  },
+
+  /**
+   * Save the current sorting
+   */
+  save: function save() {
+    var store = this.options.store;
+    store && store.set && store.set(this);
+  },
+
+  /**
+   * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+   * @param   {HTMLElement}  el
+   * @param   {String}       [selector]  default: `options.draggable`
+   * @returns {HTMLElement|null}
+   */
+  closest: function closest$1(el, selector) {
+    return closest(el, selector || this.options.draggable, this.el, false);
+  },
+
+  /**
+   * Set/get option
+   * @param   {string} name
+   * @param   {*}      [value]
+   * @returns {*}
+   */
+  option: function option(name, value) {
+    var options = this.options;
+
+    if (value === void 0) {
+      return options[name];
+    } else {
+      var modifiedValue = PluginManager.modifyOption(this, name, value);
+
+      if (typeof modifiedValue !== 'undefined') {
+        options[name] = modifiedValue;
+      } else {
+        options[name] = value;
+      }
+
+      if (name === 'group') {
+        _prepareGroup(options);
+      }
+    }
+  },
+
+  /**
+   * Destroy
+   */
+  destroy: function destroy() {
+    pluginEvent('destroy', this);
+    var el = this.el;
+    el[expando] = null;
+    off(el, 'mousedown', this._onTapStart);
+    off(el, 'touchstart', this._onTapStart);
+    off(el, 'pointerdown', this._onTapStart);
+
+    if (this.nativeDraggable) {
+      off(el, 'dragover', this);
+      off(el, 'dragenter', this);
+    } // Remove draggable attributes
+
+
+    Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
+      el.removeAttribute('draggable');
+    });
+
+    this._onDrop();
+
+    this._disableDelayedDragEvents();
+
+    sortables.splice(sortables.indexOf(this.el), 1);
+    this.el = el = null;
+  },
+  _hideClone: function _hideClone() {
+    if (!cloneHidden) {
+      pluginEvent('hideClone', this);
+      if (Sortable.eventCanceled) return;
+      css(cloneEl, 'display', 'none');
+
+      if (this.options.removeCloneOnHide && cloneEl.parentNode) {
+        cloneEl.parentNode.removeChild(cloneEl);
+      }
+
+      cloneHidden = true;
+    }
+  },
+  _showClone: function _showClone(putSortable) {
+    if (putSortable.lastPutMode !== 'clone') {
+      this._hideClone();
+
+      return;
+    }
+
+    if (cloneHidden) {
+      pluginEvent('showClone', this);
+      if (Sortable.eventCanceled) return; // show clone at dragEl or original position
+
+      if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
+        rootEl.insertBefore(cloneEl, dragEl);
+      } else if (nextEl) {
+        rootEl.insertBefore(cloneEl, nextEl);
+      } else {
+        rootEl.appendChild(cloneEl);
+      }
+
+      if (this.options.group.revertClone) {
+        this.animate(dragEl, cloneEl);
+      }
+
+      css(cloneEl, 'display', '');
+      cloneHidden = false;
+    }
+  }
+};
+
+function _globalDragOver(
+/**Event*/
+evt) {
+  if (evt.dataTransfer) {
+    evt.dataTransfer.dropEffect = 'move';
+  }
+
+  evt.cancelable && evt.preventDefault();
+}
+
+function _onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
+  var evt,
+      sortable = fromEl[expando],
+      onMoveFn = sortable.options.onMove,
+      retVal; // Support for new CustomEvent feature
+
+  if (window.CustomEvent && !IE11OrLess && !Edge) {
+    evt = new CustomEvent('move', {
+      bubbles: true,
+      cancelable: true
+    });
+  } else {
+    evt = document.createEvent('Event');
+    evt.initEvent('move', true, true);
+  }
+
+  evt.to = toEl;
+  evt.from = fromEl;
+  evt.dragged = dragEl;
+  evt.draggedRect = dragRect;
+  evt.related = targetEl || toEl;
+  evt.relatedRect = targetRect || getRect(toEl);
+  evt.willInsertAfter = willInsertAfter;
+  evt.originalEvent = originalEvent;
+  fromEl.dispatchEvent(evt);
+
+  if (onMoveFn) {
+    retVal = onMoveFn.call(sortable, evt, originalEvent);
+  }
+
+  return retVal;
+}
+
+function _disableDraggable(el) {
+  el.draggable = false;
+}
+
+function _unsilent() {
+  _silent = false;
+}
+
+function _ghostIsLast(evt, vertical, sortable) {
+  var rect = getRect(lastChild(sortable.el, sortable.options.draggable));
+  var spacer = 10;
+  return vertical ? evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left : evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer;
+}
+
+function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
+  var mouseOnAxis = vertical ? evt.clientY : evt.clientX,
+      targetLength = vertical ? targetRect.height : targetRect.width,
+      targetS1 = vertical ? targetRect.top : targetRect.left,
+      targetS2 = vertical ? targetRect.bottom : targetRect.right,
+      invert = false;
+
+  if (!invertSwap) {
+    // Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
+    if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) {
+      // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
+      // check if past first invert threshold on side opposite of lastDirection
+      if (!pastFirstInvertThresh && (lastDirection === 1 ? mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2 : mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2)) {
+        // past first invert threshold, do not restrict inverted threshold to dragEl shadow
+        pastFirstInvertThresh = true;
+      }
+
+      if (!pastFirstInvertThresh) {
+        // dragEl shadow (target move distance shadow)
+        if (lastDirection === 1 ? mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
+        : mouseOnAxis > targetS2 - targetMoveDistance) {
+          return -lastDirection;
+        }
+      } else {
+        invert = true;
+      }
+    } else {
+      // Regular
+      if (mouseOnAxis > targetS1 + targetLength * (1 - swapThreshold) / 2 && mouseOnAxis < targetS2 - targetLength * (1 - swapThreshold) / 2) {
+        return _getInsertDirection(target);
+      }
+    }
+  }
+
+  invert = invert || invertSwap;
+
+  if (invert) {
+    // Invert of regular
+    if (mouseOnAxis < targetS1 + targetLength * invertedSwapThreshold / 2 || mouseOnAxis > targetS2 - targetLength * invertedSwapThreshold / 2) {
+      return mouseOnAxis > targetS1 + targetLength / 2 ? 1 : -1;
+    }
+  }
+
+  return 0;
+}
+/**
+ * Gets the direction dragEl must be swapped relative to target in order to make it
+ * seem that dragEl has been "inserted" into that element's position
+ * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
+ * @return {Number}                   Direction dragEl must be swapped
+ */
+
+
+function _getInsertDirection(target) {
+  if (index(dragEl) < index(target)) {
+    return 1;
+  } else {
+    return -1;
+  }
+}
+/**
+ * Generate id
+ * @param   {HTMLElement} el
+ * @returns {String}
+ * @private
+ */
+
+
+function _generateId(el) {
+  var str = el.tagName + el.className + el.src + el.href + el.textContent,
+      i = str.length,
+      sum = 0;
+
+  while (i--) {
+    sum += str.charCodeAt(i);
+  }
+
+  return sum.toString(36);
+}
+
+function _saveInputCheckedState(root) {
+  savedInputChecked.length = 0;
+  var inputs = root.getElementsByTagName('input');
+  var idx = inputs.length;
+
+  while (idx--) {
+    var el = inputs[idx];
+    el.checked && savedInputChecked.push(el);
+  }
+}
+
+function _nextTick(fn) {
+  return setTimeout(fn, 0);
+}
+
+function _cancelNextTick(id) {
+  return clearTimeout(id);
+} // Fixed #973:
+
+
+if (documentExists) {
+  on(document, 'touchmove', function (evt) {
+    if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
+      evt.preventDefault();
+    }
+  });
+} // Export utils
+
+
+Sortable.utils = {
+  on: on,
+  off: off,
+  css: css,
+  find: find,
+  is: function is(el, selector) {
+    return !!closest(el, selector, el, false);
+  },
+  extend: extend,
+  throttle: throttle,
+  closest: closest,
+  toggleClass: toggleClass,
+  clone: clone,
+  index: index,
+  nextTick: _nextTick,
+  cancelNextTick: _cancelNextTick,
+  detectDirection: _detectDirection,
+  getChild: getChild
+};
+/**
+ * Get the Sortable instance of an element
+ * @param  {HTMLElement} element The element
+ * @return {Sortable|undefined}         The instance of Sortable
+ */
+
+Sortable.get = function (element) {
+  return element[expando];
+};
+/**
+ * Mount a plugin to Sortable
+ * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
+ */
+
+
+Sortable.mount = function () {
+  for (var _len = arguments.length, plugins = new Array(_len), _key = 0; _key < _len; _key++) {
+    plugins[_key] = arguments[_key];
+  }
+
+  if (plugins[0].constructor === Array) plugins = plugins[0];
+  plugins.forEach(function (plugin) {
+    if (!plugin.prototype || !plugin.prototype.constructor) {
+      throw "Sortable: Mounted plugin must be a constructor function, not ".concat({}.toString.call(plugin));
+    }
+
+    if (plugin.utils) Sortable.utils = _objectSpread({}, Sortable.utils, plugin.utils);
+    PluginManager.mount(plugin);
+  });
+};
+/**
+ * Create sortable instance
+ * @param {HTMLElement}  el
+ * @param {Object}      [options]
+ */
+
+
+Sortable.create = function (el, options) {
+  return new Sortable(el, options);
+}; // Export
+
+
+Sortable.version = version;
+
+var autoScrolls = [],
+    scrollEl,
+    scrollRootEl,
+    scrolling = false,
+    lastAutoScrollX,
+    lastAutoScrollY,
+    touchEvt$1,
+    pointerElemChangedInterval;
+
+function AutoScrollPlugin() {
+  function AutoScroll() {
+    this.defaults = {
+      scroll: true,
+      scrollSensitivity: 30,
+      scrollSpeed: 10,
+      bubbleScroll: true
+    }; // Bind all private methods
+
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    }
+  }
+
+  AutoScroll.prototype = {
+    dragStarted: function dragStarted(_ref) {
+      var originalEvent = _ref.originalEvent;
+
+      if (this.sortable.nativeDraggable) {
+        on(document, 'dragover', this._handleAutoScroll);
+      } else {
+        if (this.options.supportPointer) {
+          on(document, 'pointermove', this._handleFallbackAutoScroll);
+        } else if (originalEvent.touches) {
+          on(document, 'touchmove', this._handleFallbackAutoScroll);
+        } else {
+          on(document, 'mousemove', this._handleFallbackAutoScroll);
+        }
+      }
+    },
+    dragOverCompleted: function dragOverCompleted(_ref2) {
+      var originalEvent = _ref2.originalEvent;
+
+      // For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
+      if (!this.options.dragOverBubble && !originalEvent.rootEl) {
+        this._handleAutoScroll(originalEvent);
+      }
+    },
+    drop: function drop() {
+      if (this.sortable.nativeDraggable) {
+        off(document, 'dragover', this._handleAutoScroll);
+      } else {
+        off(document, 'pointermove', this._handleFallbackAutoScroll);
+        off(document, 'touchmove', this._handleFallbackAutoScroll);
+        off(document, 'mousemove', this._handleFallbackAutoScroll);
+      }
+
+      clearPointerElemChangedInterval();
+      clearAutoScrolls();
+      cancelThrottle();
+    },
+    nulling: function nulling() {
+      touchEvt$1 = scrollRootEl = scrollEl = scrolling = pointerElemChangedInterval = lastAutoScrollX = lastAutoScrollY = null;
+      autoScrolls.length = 0;
+    },
+    _handleFallbackAutoScroll: function _handleFallbackAutoScroll(evt) {
+      this._handleAutoScroll(evt, true);
+    },
+    _handleAutoScroll: function _handleAutoScroll(evt, fallback) {
+      var _this = this;
+
+      var x = (evt.touches ? evt.touches[0] : evt).clientX,
+          y = (evt.touches ? evt.touches[0] : evt).clientY,
+          elem = document.elementFromPoint(x, y);
+      touchEvt$1 = evt; // IE does not seem to have native autoscroll,
+      // Edge's autoscroll seems too conditional,
+      // MACOS Safari does not have autoscroll,
+      // Firefox and Chrome are good
+
+      if (fallback || Edge || IE11OrLess || Safari) {
+        autoScroll(evt, this.options, elem, fallback); // Listener for pointer element change
+
+        var ogElemScroller = getParentAutoScrollElement(elem, true);
+
+        if (scrolling && (!pointerElemChangedInterval || x !== lastAutoScrollX || y !== lastAutoScrollY)) {
+          pointerElemChangedInterval && clearPointerElemChangedInterval(); // Detect for pointer elem change, emulating native DnD behaviour
+
+          pointerElemChangedInterval = setInterval(function () {
+            var newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
+
+            if (newElem !== ogElemScroller) {
+              ogElemScroller = newElem;
+              clearAutoScrolls();
+            }
+
+            autoScroll(evt, _this.options, newElem, fallback);
+          }, 10);
+          lastAutoScrollX = x;
+          lastAutoScrollY = y;
+        }
+      } else {
+        // if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
+        if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
+          clearAutoScrolls();
+          return;
+        }
+
+        autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
+      }
+    }
+  };
+  return _extends(AutoScroll, {
+    pluginName: 'scroll',
+    initializeByDefault: true
+  });
+}
+
+function clearAutoScrolls() {
+  autoScrolls.forEach(function (autoScroll) {
+    clearInterval(autoScroll.pid);
+  });
+  autoScrolls = [];
+}
+
+function clearPointerElemChangedInterval() {
+  clearInterval(pointerElemChangedInterval);
+}
+
+var autoScroll = throttle(function (evt, options, rootEl, isFallback) {
+  // Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+  if (!options.scroll) return;
+  var x = (evt.touches ? evt.touches[0] : evt).clientX,
+      y = (evt.touches ? evt.touches[0] : evt).clientY,
+      sens = options.scrollSensitivity,
+      speed = options.scrollSpeed,
+      winScroller = getWindowScrollingElement();
+  var scrollThisInstance = false,
+      scrollCustomFn; // New scroll root, set scrollEl
+
+  if (scrollRootEl !== rootEl) {
+    scrollRootEl = rootEl;
+    clearAutoScrolls();
+    scrollEl = options.scroll;
+    scrollCustomFn = options.scrollFn;
+
+    if (scrollEl === true) {
+      scrollEl = getParentAutoScrollElement(rootEl, true);
+    }
+  }
+
+  var layersOut = 0;
+  var currentParent = scrollEl;
+
+  do {
+    var el = currentParent,
+        rect = getRect(el),
+        top = rect.top,
+        bottom = rect.bottom,
+        left = rect.left,
+        right = rect.right,
+        width = rect.width,
+        height = rect.height,
+        canScrollX = void 0,
+        canScrollY = void 0,
+        scrollWidth = el.scrollWidth,
+        scrollHeight = el.scrollHeight,
+        elCSS = css(el),
+        scrollPosX = el.scrollLeft,
+        scrollPosY = el.scrollTop;
+
+    if (el === winScroller) {
+      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
+      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
+    } else {
+      canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
+      canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
+    }
+
+    var vx = canScrollX && (Math.abs(right - x) <= sens && scrollPosX + width < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
+    var vy = canScrollY && (Math.abs(bottom - y) <= sens && scrollPosY + height < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
+
+    if (!autoScrolls[layersOut]) {
+      for (var i = 0; i <= layersOut; i++) {
+        if (!autoScrolls[i]) {
+          autoScrolls[i] = {};
+        }
+      }
+    }
+
+    if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
+      autoScrolls[layersOut].el = el;
+      autoScrolls[layersOut].vx = vx;
+      autoScrolls[layersOut].vy = vy;
+      clearInterval(autoScrolls[layersOut].pid);
+
+      if (vx != 0 || vy != 0) {
+        scrollThisInstance = true;
+        /* jshint loopfunc:true */
+
+        autoScrolls[layersOut].pid = setInterval(function () {
+          // emulate drag over during autoscroll (fallback), emulating native DnD behaviour
+          if (isFallback && this.layer === 0) {
+            Sortable.active._onTouchMove(touchEvt$1); // To move ghost if it is positioned absolutely
+
+          }
+
+          var scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
+          var scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
+
+          if (typeof scrollCustomFn === 'function') {
+            if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt$1, autoScrolls[this.layer].el) !== 'continue') {
+              return;
+            }
+          }
+
+          scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
+        }.bind({
+          layer: layersOut
+        }), 24);
+      }
+    }
+
+    layersOut++;
+  } while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
+
+  scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
+}, 30);
+
+var drop = function drop(_ref) {
+  var originalEvent = _ref.originalEvent,
+      putSortable = _ref.putSortable,
+      dragEl = _ref.dragEl,
+      activeSortable = _ref.activeSortable,
+      dispatchSortableEvent = _ref.dispatchSortableEvent,
+      hideGhostForTarget = _ref.hideGhostForTarget,
+      unhideGhostForTarget = _ref.unhideGhostForTarget;
+  if (!originalEvent) return;
+  var toSortable = putSortable || activeSortable;
+  hideGhostForTarget();
+  var touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
+  var target = document.elementFromPoint(touch.clientX, touch.clientY);
+  unhideGhostForTarget();
+
+  if (toSortable && !toSortable.el.contains(target)) {
+    dispatchSortableEvent('spill');
+    this.onSpill({
+      dragEl: dragEl,
+      putSortable: putSortable
+    });
+  }
+};
+
+function Revert() {}
+
+Revert.prototype = {
+  startIndex: null,
+  dragStart: function dragStart(_ref2) {
+    var oldDraggableIndex = _ref2.oldDraggableIndex;
+    this.startIndex = oldDraggableIndex;
+  },
+  onSpill: function onSpill(_ref3) {
+    var dragEl = _ref3.dragEl,
+        putSortable = _ref3.putSortable;
+    this.sortable.captureAnimationState();
+
+    if (putSortable) {
+      putSortable.captureAnimationState();
+    }
+
+    var nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
+
+    if (nextSibling) {
+      this.sortable.el.insertBefore(dragEl, nextSibling);
+    } else {
+      this.sortable.el.appendChild(dragEl);
+    }
+
+    this.sortable.animateAll();
+
+    if (putSortable) {
+      putSortable.animateAll();
+    }
+  },
+  drop: drop
+};
+
+_extends(Revert, {
+  pluginName: 'revertOnSpill'
+});
+
+function Remove() {}
+
+Remove.prototype = {
+  onSpill: function onSpill(_ref4) {
+    var dragEl = _ref4.dragEl,
+        putSortable = _ref4.putSortable;
+    var parentSortable = putSortable || this.sortable;
+    parentSortable.captureAnimationState();
+    dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
+    parentSortable.animateAll();
+  },
+  drop: drop
+};
+
+_extends(Remove, {
+  pluginName: 'removeOnSpill'
+});
+
+var lastSwapEl;
+
+function SwapPlugin() {
+  function Swap() {
+    this.defaults = {
+      swapClass: 'sortable-swap-highlight'
+    };
+  }
+
+  Swap.prototype = {
+    dragStart: function dragStart(_ref) {
+      var dragEl = _ref.dragEl;
+      lastSwapEl = dragEl;
+    },
+    dragOverValid: function dragOverValid(_ref2) {
+      var completed = _ref2.completed,
+          target = _ref2.target,
+          onMove = _ref2.onMove,
+          activeSortable = _ref2.activeSortable,
+          changed = _ref2.changed,
+          cancel = _ref2.cancel;
+      if (!activeSortable.options.swap) return;
+      var el = this.sortable.el,
+          options = this.options;
+
+      if (target && target !== el) {
+        var prevSwapEl = lastSwapEl;
+
+        if (onMove(target) !== false) {
+          toggleClass(target, options.swapClass, true);
+          lastSwapEl = target;
+        } else {
+          lastSwapEl = null;
+        }
+
+        if (prevSwapEl && prevSwapEl !== lastSwapEl) {
+          toggleClass(prevSwapEl, options.swapClass, false);
+        }
+      }
+
+      changed();
+      completed(true);
+      cancel();
+    },
+    drop: function drop(_ref3) {
+      var activeSortable = _ref3.activeSortable,
+          putSortable = _ref3.putSortable,
+          dragEl = _ref3.dragEl;
+      var toSortable = putSortable || this.sortable;
+      var options = this.options;
+      lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
+
+      if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
+        if (dragEl !== lastSwapEl) {
+          toSortable.captureAnimationState();
+          if (toSortable !== activeSortable) activeSortable.captureAnimationState();
+          swapNodes(dragEl, lastSwapEl);
+          toSortable.animateAll();
+          if (toSortable !== activeSortable) activeSortable.animateAll();
+        }
+      }
+    },
+    nulling: function nulling() {
+      lastSwapEl = null;
+    }
+  };
+  return _extends(Swap, {
+    pluginName: 'swap',
+    eventProperties: function eventProperties() {
+      return {
+        swapItem: lastSwapEl
+      };
+    }
+  });
+}
+
+function swapNodes(n1, n2) {
+  var p1 = n1.parentNode,
+      p2 = n2.parentNode,
+      i1,
+      i2;
+  if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
+  i1 = index(n1);
+  i2 = index(n2);
+
+  if (p1.isEqualNode(p2) && i1 < i2) {
+    i2++;
+  }
+
+  p1.insertBefore(n2, p1.children[i1]);
+  p2.insertBefore(n1, p2.children[i2]);
+}
+
+var multiDragElements = [],
+    multiDragClones = [],
+    lastMultiDragSelect,
+    // for selection with modifier key down (SHIFT)
+multiDragSortable,
+    initialFolding = false,
+    // Initial multi-drag fold when drag started
+folding = false,
+    // Folding any other time
+dragStarted = false,
+    dragEl$1,
+    clonesFromRect,
+    clonesHidden;
+
+function MultiDragPlugin() {
+  function MultiDrag(sortable) {
+    // Bind all private methods
+    for (var fn in this) {
+      if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+        this[fn] = this[fn].bind(this);
+      }
+    }
+
+    if (sortable.options.supportPointer) {
+      on(document, 'pointerup', this._deselectMultiDrag);
+    } else {
+      on(document, 'mouseup', this._deselectMultiDrag);
+      on(document, 'touchend', this._deselectMultiDrag);
+    }
+
+    on(document, 'keydown', this._checkKeyDown);
+    on(document, 'keyup', this._checkKeyUp);
+    this.defaults = {
+      selectedClass: 'sortable-selected',
+      multiDragKey: null,
+      setData: function setData(dataTransfer, dragEl) {
+        var data = '';
+
+        if (multiDragElements.length && multiDragSortable === sortable) {
+          multiDragElements.forEach(function (multiDragElement, i) {
+            data += (!i ? '' : ', ') + multiDragElement.textContent;
+          });
+        } else {
+          data = dragEl.textContent;
+        }
+
+        dataTransfer.setData('Text', data);
+      }
+    };
+  }
+
+  MultiDrag.prototype = {
+    multiDragKeyDown: false,
+    isMultiDrag: false,
+    delayStartGlobal: function delayStartGlobal(_ref) {
+      var dragged = _ref.dragEl;
+      dragEl$1 = dragged;
+    },
+    delayEnded: function delayEnded() {
+      this.isMultiDrag = ~multiDragElements.indexOf(dragEl$1);
+    },
+    setupClone: function setupClone(_ref2) {
+      var sortable = _ref2.sortable,
+          cancel = _ref2.cancel;
+      if (!this.isMultiDrag) return;
+
+      for (var i = 0; i < multiDragElements.length; i++) {
+        multiDragClones.push(clone(multiDragElements[i]));
+        multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
+        multiDragClones[i].draggable = false;
+        multiDragClones[i].style['will-change'] = '';
+        toggleClass(multiDragClones[i], this.options.selectedClass, false);
+        multiDragElements[i] === dragEl$1 && toggleClass(multiDragClones[i], this.options.chosenClass, false);
+      }
+
+      sortable._hideClone();
+
+      cancel();
+    },
+    clone: function clone(_ref3) {
+      var sortable = _ref3.sortable,
+          rootEl = _ref3.rootEl,
+          dispatchSortableEvent = _ref3.dispatchSortableEvent,
+          cancel = _ref3.cancel;
+      if (!this.isMultiDrag) return;
+
+      if (!this.options.removeCloneOnHide) {
+        if (multiDragElements.length && multiDragSortable === sortable) {
+          insertMultiDragClones(true, rootEl);
+          dispatchSortableEvent('clone');
+          cancel();
+        }
+      }
+    },
+    showClone: function showClone(_ref4) {
+      var cloneNowShown = _ref4.cloneNowShown,
+          rootEl = _ref4.rootEl,
+          cancel = _ref4.cancel;
+      if (!this.isMultiDrag) return;
+      insertMultiDragClones(false, rootEl);
+      multiDragClones.forEach(function (clone) {
+        css(clone, 'display', '');
+      });
+      cloneNowShown();
+      clonesHidden = false;
+      cancel();
+    },
+    hideClone: function hideClone(_ref5) {
+      var _this = this;
+
+      var sortable = _ref5.sortable,
+          cloneNowHidden = _ref5.cloneNowHidden,
+          cancel = _ref5.cancel;
+      if (!this.isMultiDrag) return;
+      multiDragClones.forEach(function (clone) {
+        css(clone, 'display', 'none');
+
+        if (_this.options.removeCloneOnHide && clone.parentNode) {
+          clone.parentNode.removeChild(clone);
+        }
+      });
+      cloneNowHidden();
+      clonesHidden = true;
+      cancel();
+    },
+    dragStartGlobal: function dragStartGlobal(_ref6) {
+      var sortable = _ref6.sortable;
+
+      if (!this.isMultiDrag && multiDragSortable) {
+        multiDragSortable.multiDrag._deselectMultiDrag();
+      }
+
+      multiDragElements.forEach(function (multiDragElement) {
+        multiDragElement.sortableIndex = index(multiDragElement);
+      }); // Sort multi-drag elements
+
+      multiDragElements = multiDragElements.sort(function (a, b) {
+        return a.sortableIndex - b.sortableIndex;
+      });
+      dragStarted = true;
+    },
+    dragStarted: function dragStarted(_ref7) {
+      var _this2 = this;
+
+      var sortable = _ref7.sortable;
+      if (!this.isMultiDrag) return;
+
+      if (this.options.sort) {
+        // Capture rects,
+        // hide multi drag elements (by positioning them absolute),
+        // set multi drag elements rects to dragRect,
+        // show multi drag elements,
+        // animate to rects,
+        // unset rects & remove from DOM
+        sortable.captureAnimationState();
+
+        if (this.options.animation) {
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            css(multiDragElement, 'position', 'absolute');
+          });
+          var dragRect = getRect(dragEl$1, false, true, true);
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            setRect(multiDragElement, dragRect);
+          });
+          folding = true;
+          initialFolding = true;
+        }
+      }
+
+      sortable.animateAll(function () {
+        folding = false;
+        initialFolding = false;
+
+        if (_this2.options.animation) {
+          multiDragElements.forEach(function (multiDragElement) {
+            unsetRect(multiDragElement);
+          });
+        } // Remove all auxiliary multidrag items from el, if sorting enabled
+
+
+        if (_this2.options.sort) {
+          removeMultiDragElements();
+        }
+      });
+    },
+    dragOver: function dragOver(_ref8) {
+      var target = _ref8.target,
+          completed = _ref8.completed,
+          cancel = _ref8.cancel;
+
+      if (folding && ~multiDragElements.indexOf(target)) {
+        completed(false);
+        cancel();
+      }
+    },
+    revert: function revert(_ref9) {
+      var fromSortable = _ref9.fromSortable,
+          rootEl = _ref9.rootEl,
+          sortable = _ref9.sortable,
+          dragRect = _ref9.dragRect;
+
+      if (multiDragElements.length > 1) {
+        // Setup unfold animation
+        multiDragElements.forEach(function (multiDragElement) {
+          sortable.addAnimationState({
+            target: multiDragElement,
+            rect: folding ? getRect(multiDragElement) : dragRect
+          });
+          unsetRect(multiDragElement);
+          multiDragElement.fromRect = dragRect;
+          fromSortable.removeAnimationState(multiDragElement);
+        });
+        folding = false;
+        insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
+      }
+    },
+    dragOverCompleted: function dragOverCompleted(_ref10) {
+      var sortable = _ref10.sortable,
+          isOwner = _ref10.isOwner,
+          insertion = _ref10.insertion,
+          activeSortable = _ref10.activeSortable,
+          parentEl = _ref10.parentEl,
+          putSortable = _ref10.putSortable;
+      var options = this.options;
+
+      if (insertion) {
+        // Clones must be hidden before folding animation to capture dragRectAbsolute properly
+        if (isOwner) {
+          activeSortable._hideClone();
+        }
+
+        initialFolding = false; // If leaving sort:false root, or already folding - Fold to new location
+
+        if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
+          // Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
+          var dragRectAbsolute = getRect(dragEl$1, false, true, true);
+          multiDragElements.forEach(function (multiDragElement) {
+            if (multiDragElement === dragEl$1) return;
+            setRect(multiDragElement, dragRectAbsolute); // Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
+            // while folding, and so that we can capture them again because old sortable will no longer be fromSortable
+
+            parentEl.appendChild(multiDragElement);
+          });
+          folding = true;
+        } // Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
+
+
+        if (!isOwner) {
+          // Only remove if not folding (folding will remove them anyways)
+          if (!folding) {
+            removeMultiDragElements();
+          }
+
+          if (multiDragElements.length > 1) {
+            var clonesHiddenBefore = clonesHidden;
+
+            activeSortable._showClone(sortable); // Unfold animation for clones if showing from hidden
+
+
+            if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
+              multiDragClones.forEach(function (clone) {
+                activeSortable.addAnimationState({
+                  target: clone,
+                  rect: clonesFromRect
+                });
+                clone.fromRect = clonesFromRect;
+                clone.thisAnimationDuration = null;
+              });
+            }
+          } else {
+            activeSortable._showClone(sortable);
+          }
+        }
+      }
+    },
+    dragOverAnimationCapture: function dragOverAnimationCapture(_ref11) {
+      var dragRect = _ref11.dragRect,
+          isOwner = _ref11.isOwner,
+          activeSortable = _ref11.activeSortable;
+      multiDragElements.forEach(function (multiDragElement) {
+        multiDragElement.thisAnimationDuration = null;
+      });
+
+      if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
+        clonesFromRect = _extends({}, dragRect);
+        var dragMatrix = matrix(dragEl$1, true);
+        clonesFromRect.top -= dragMatrix.f;
+        clonesFromRect.left -= dragMatrix.e;
+      }
+    },
+    dragOverAnimationComplete: function dragOverAnimationComplete() {
+      if (folding) {
+        folding = false;
+        removeMultiDragElements();
+      }
+    },
+    drop: function drop(_ref12) {
+      var evt = _ref12.originalEvent,
+          rootEl = _ref12.rootEl,
+          parentEl = _ref12.parentEl,
+          sortable = _ref12.sortable,
+          dispatchSortableEvent = _ref12.dispatchSortableEvent,
+          oldIndex = _ref12.oldIndex,
+          putSortable = _ref12.putSortable;
+      var toSortable = putSortable || this.sortable;
+      if (!evt) return;
+      var options = this.options,
+          children = parentEl.children; // Multi-drag selection
+
+      if (!dragStarted) {
+        if (options.multiDragKey && !this.multiDragKeyDown) {
+          this._deselectMultiDrag();
+        }
+
+        toggleClass(dragEl$1, options.selectedClass, !~multiDragElements.indexOf(dragEl$1));
+
+        if (!~multiDragElements.indexOf(dragEl$1)) {
+          multiDragElements.push(dragEl$1);
+          dispatchEvent({
+            sortable: sortable,
+            rootEl: rootEl,
+            name: 'select',
+            targetEl: dragEl$1,
+            originalEvt: evt
+          }); // Modifier activated, select from last to dragEl
+
+          if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
+            var lastIndex = index(lastMultiDragSelect),
+                currentIndex = index(dragEl$1);
+
+            if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
+              // Must include lastMultiDragSelect (select it), in case modified selection from no selection
+              // (but previous selection existed)
+              var n, i;
+
+              if (currentIndex > lastIndex) {
+                i = lastIndex;
+                n = currentIndex;
+              } else {
+                i = currentIndex;
+                n = lastIndex + 1;
+              }
+
+              for (; i < n; i++) {
+                if (~multiDragElements.indexOf(children[i])) continue;
+                toggleClass(children[i], options.selectedClass, true);
+                multiDragElements.push(children[i]);
+                dispatchEvent({
+                  sortable: sortable,
+                  rootEl: rootEl,
+                  name: 'select',
+                  targetEl: children[i],
+                  originalEvt: evt
+                });
+              }
+            }
+          } else {
+            lastMultiDragSelect = dragEl$1;
+          }
+
+          multiDragSortable = toSortable;
+        } else {
+          multiDragElements.splice(multiDragElements.indexOf(dragEl$1), 1);
+          lastMultiDragSelect = null;
+          dispatchEvent({
+            sortable: sortable,
+            rootEl: rootEl,
+            name: 'deselect',
+            targetEl: dragEl$1,
+            originalEvt: evt
+          });
+        }
+      } // Multi-drag drop
+
+
+      if (dragStarted && this.isMultiDrag) {
+        // Do not "unfold" after around dragEl if reverted
+        if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
+          var dragRect = getRect(dragEl$1),
+              multiDragIndex = index(dragEl$1, ':not(.' + this.options.selectedClass + ')');
+          if (!initialFolding && options.animation) dragEl$1.thisAnimationDuration = null;
+          toSortable.captureAnimationState();
+
+          if (!initialFolding) {
+            if (options.animation) {
+              dragEl$1.fromRect = dragRect;
+              multiDragElements.forEach(function (multiDragElement) {
+                multiDragElement.thisAnimationDuration = null;
+
+                if (multiDragElement !== dragEl$1) {
+                  var rect = folding ? getRect(multiDragElement) : dragRect;
+                  multiDragElement.fromRect = rect; // Prepare unfold animation
+
+                  toSortable.addAnimationState({
+                    target: multiDragElement,
+                    rect: rect
+                  });
+                }
+              });
+            } // Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
+            // properly they must all be removed
+
+
+            removeMultiDragElements();
+            multiDragElements.forEach(function (multiDragElement) {
+              if (children[multiDragIndex]) {
+                parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
+              } else {
+                parentEl.appendChild(multiDragElement);
+              }
+
+              multiDragIndex++;
+            }); // If initial folding is done, the elements may have changed position because they are now
+            // unfolding around dragEl, even though dragEl may not have his index changed, so update event
+            // must be fired here as Sortable will not.
+
+            if (oldIndex === index(dragEl$1)) {
+              var update = false;
+              multiDragElements.forEach(function (multiDragElement) {
+                if (multiDragElement.sortableIndex !== index(multiDragElement)) {
+                  update = true;
+                  return;
+                }
+              });
+
+              if (update) {
+                dispatchSortableEvent('update');
+              }
+            }
+          } // Must be done after capturing individual rects (scroll bar)
+
+
+          multiDragElements.forEach(function (multiDragElement) {
+            unsetRect(multiDragElement);
+          });
+          toSortable.animateAll();
+        }
+
+        multiDragSortable = toSortable;
+      } // Remove clones if necessary
+
+
+      if (rootEl === parentEl || putSortable && putSortable.lastPutMode !== 'clone') {
+        multiDragClones.forEach(function (clone) {
+          clone.parentNode && clone.parentNode.removeChild(clone);
+        });
+      }
+    },
+    nullingGlobal: function nullingGlobal() {
+      this.isMultiDrag = dragStarted = false;
+      multiDragClones.length = 0;
+    },
+    destroyGlobal: function destroyGlobal() {
+      this._deselectMultiDrag();
+
+      off(document, 'pointerup', this._deselectMultiDrag);
+      off(document, 'mouseup', this._deselectMultiDrag);
+      off(document, 'touchend', this._deselectMultiDrag);
+      off(document, 'keydown', this._checkKeyDown);
+      off(document, 'keyup', this._checkKeyUp);
+    },
+    _deselectMultiDrag: function _deselectMultiDrag(evt) {
+      if (typeof dragStarted !== "undefined" && dragStarted) return; // Only deselect if selection is in this sortable
+
+      if (multiDragSortable !== this.sortable) return; // Only deselect if target is not item in this sortable
+
+      if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return; // Only deselect if left click
+
+      if (evt && evt.button !== 0) return;
+
+      while (multiDragElements.length) {
+        var el = multiDragElements[0];
+        toggleClass(el, this.options.selectedClass, false);
+        multiDragElements.shift();
+        dispatchEvent({
+          sortable: this.sortable,
+          rootEl: this.sortable.el,
+          name: 'deselect',
+          targetEl: el,
+          originalEvt: evt
+        });
+      }
+    },
+    _checkKeyDown: function _checkKeyDown(evt) {
+      if (evt.key === this.options.multiDragKey) {
+        this.multiDragKeyDown = true;
+      }
+    },
+    _checkKeyUp: function _checkKeyUp(evt) {
+      if (evt.key === this.options.multiDragKey) {
+        this.multiDragKeyDown = false;
+      }
+    }
+  };
+  return _extends(MultiDrag, {
+    // Static methods & properties
+    pluginName: 'multiDrag',
+    utils: {
+      /**
+       * Selects the provided multi-drag item
+       * @param  {HTMLElement} el    The element to be selected
+       */
+      select: function select(el) {
+        var sortable = el.parentNode[expando];
+        if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
+
+        if (multiDragSortable && multiDragSortable !== sortable) {
+          multiDragSortable.multiDrag._deselectMultiDrag();
+
+          multiDragSortable = sortable;
+        }
+
+        toggleClass(el, sortable.options.selectedClass, true);
+        multiDragElements.push(el);
+      },
+
+      /**
+       * Deselects the provided multi-drag item
+       * @param  {HTMLElement} el    The element to be deselected
+       */
+      deselect: function deselect(el) {
+        var sortable = el.parentNode[expando],
+            index = multiDragElements.indexOf(el);
+        if (!sortable || !sortable.options.multiDrag || !~index) return;
+        toggleClass(el, sortable.options.selectedClass, false);
+        multiDragElements.splice(index, 1);
+      }
+    },
+    eventProperties: function eventProperties() {
+      var _this3 = this;
+
+      var oldIndicies = [],
+          newIndicies = [];
+      multiDragElements.forEach(function (multiDragElement) {
+        oldIndicies.push({
+          multiDragElement: multiDragElement,
+          index: multiDragElement.sortableIndex
+        }); // multiDragElements will already be sorted if folding
+
+        var newIndex;
+
+        if (folding && multiDragElement !== dragEl$1) {
+          newIndex = -1;
+        } else if (folding) {
+          newIndex = index(multiDragElement, ':not(.' + _this3.options.selectedClass + ')');
+        } else {
+          newIndex = index(multiDragElement);
+        }
+
+        newIndicies.push({
+          multiDragElement: multiDragElement,
+          index: newIndex
+        });
+      });
+      return {
+        items: _toConsumableArray(multiDragElements),
+        clones: [].concat(multiDragClones),
+        oldIndicies: oldIndicies,
+        newIndicies: newIndicies
+      };
+    },
+    optionListeners: {
+      multiDragKey: function multiDragKey(key) {
+        key = key.toLowerCase();
+
+        if (key === 'ctrl') {
+          key = 'Control';
+        } else if (key.length > 1) {
+          key = key.charAt(0).toUpperCase() + key.substr(1);
+        }
+
+        return key;
+      }
+    }
+  });
+}
+
+function insertMultiDragElements(clonesInserted, rootEl) {
+  multiDragElements.forEach(function (multiDragElement, i) {
+    var target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
+
+    if (target) {
+      rootEl.insertBefore(multiDragElement, target);
+    } else {
+      rootEl.appendChild(multiDragElement);
+    }
+  });
+}
+/**
+ * Insert multi-drag clones
+ * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
+ * @param  {HTMLElement} rootEl
+ */
+
+
+function insertMultiDragClones(elementsInserted, rootEl) {
+  multiDragClones.forEach(function (clone, i) {
+    var target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
+
+    if (target) {
+      rootEl.insertBefore(clone, target);
+    } else {
+      rootEl.appendChild(clone);
+    }
+  });
+}
+
+function removeMultiDragElements() {
+  multiDragElements.forEach(function (multiDragElement) {
+    if (multiDragElement === dragEl$1) return;
+    multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
+  });
+}
+
+Sortable.mount(new AutoScrollPlugin());
+Sortable.mount(Remove, Revert);
+
+export default Sortable;
+export { MultiDragPlugin as MultiDrag, Sortable, SwapPlugin as Swap };

+ 5704 - 0
public/assets/libs/Sortable/package-lock.json

@@ -0,0 +1,5704 @@
+{
+	"name": "sortablejs",
+	"version": "1.10.1",
+	"lockfileVersion": 1,
+	"requires": true,
+	"dependencies": {
+		"@babel/code-frame": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+			"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+			"dev": true,
+			"requires": {
+				"@babel/highlight": "^7.0.0"
+			}
+		},
+		"@babel/core": {
+			"version": "7.4.5",
+			"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz",
+			"integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==",
+			"dev": true,
+			"requires": {
+				"@babel/code-frame": "^7.0.0",
+				"@babel/generator": "^7.4.4",
+				"@babel/helpers": "^7.4.4",
+				"@babel/parser": "^7.4.5",
+				"@babel/template": "^7.4.4",
+				"@babel/traverse": "^7.4.5",
+				"@babel/types": "^7.4.4",
+				"convert-source-map": "^1.1.0",
+				"debug": "^4.1.0",
+				"json5": "^2.1.0",
+				"lodash": "^4.17.11",
+				"resolve": "^1.3.2",
+				"semver": "^5.4.1",
+				"source-map": "^0.5.0"
+			}
+		},
+		"@babel/generator": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz",
+			"integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.4.4",
+				"jsesc": "^2.5.1",
+				"lodash": "^4.17.11",
+				"source-map": "^0.5.0",
+				"trim-right": "^1.0.1"
+			}
+		},
+		"@babel/helper-annotate-as-pure": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz",
+			"integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-builder-binary-assignment-operator-visitor": {
+			"version": "7.1.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz",
+			"integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-explode-assignable-expression": "^7.1.0",
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-call-delegate": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz",
+			"integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-hoist-variables": "^7.4.4",
+				"@babel/traverse": "^7.4.4",
+				"@babel/types": "^7.4.4"
+			}
+		},
+		"@babel/helper-define-map": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz",
+			"integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-function-name": "^7.1.0",
+				"@babel/types": "^7.4.4",
+				"lodash": "^4.17.11"
+			}
+		},
+		"@babel/helper-explode-assignable-expression": {
+			"version": "7.1.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz",
+			"integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==",
+			"dev": true,
+			"requires": {
+				"@babel/traverse": "^7.1.0",
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-function-name": {
+			"version": "7.1.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
+			"integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-get-function-arity": "^7.0.0",
+				"@babel/template": "^7.1.0",
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-get-function-arity": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
+			"integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-hoist-variables": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz",
+			"integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.4.4"
+			}
+		},
+		"@babel/helper-member-expression-to-functions": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz",
+			"integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-module-imports": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz",
+			"integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-module-transforms": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz",
+			"integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-imports": "^7.0.0",
+				"@babel/helper-simple-access": "^7.1.0",
+				"@babel/helper-split-export-declaration": "^7.4.4",
+				"@babel/template": "^7.4.4",
+				"@babel/types": "^7.4.4",
+				"lodash": "^4.17.11"
+			}
+		},
+		"@babel/helper-optimise-call-expression": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz",
+			"integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-plugin-utils": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
+			"integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
+			"dev": true
+		},
+		"@babel/helper-regex": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz",
+			"integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==",
+			"dev": true,
+			"requires": {
+				"lodash": "^4.17.11"
+			}
+		},
+		"@babel/helper-remap-async-to-generator": {
+			"version": "7.1.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz",
+			"integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-annotate-as-pure": "^7.0.0",
+				"@babel/helper-wrap-function": "^7.1.0",
+				"@babel/template": "^7.1.0",
+				"@babel/traverse": "^7.1.0",
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-replace-supers": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz",
+			"integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-member-expression-to-functions": "^7.0.0",
+				"@babel/helper-optimise-call-expression": "^7.0.0",
+				"@babel/traverse": "^7.4.4",
+				"@babel/types": "^7.4.4"
+			}
+		},
+		"@babel/helper-simple-access": {
+			"version": "7.1.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz",
+			"integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==",
+			"dev": true,
+			"requires": {
+				"@babel/template": "^7.1.0",
+				"@babel/types": "^7.0.0"
+			}
+		},
+		"@babel/helper-split-export-declaration": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz",
+			"integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==",
+			"dev": true,
+			"requires": {
+				"@babel/types": "^7.4.4"
+			}
+		},
+		"@babel/helper-wrap-function": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz",
+			"integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-function-name": "^7.1.0",
+				"@babel/template": "^7.1.0",
+				"@babel/traverse": "^7.1.0",
+				"@babel/types": "^7.2.0"
+			}
+		},
+		"@babel/helpers": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz",
+			"integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==",
+			"dev": true,
+			"requires": {
+				"@babel/template": "^7.4.4",
+				"@babel/traverse": "^7.4.4",
+				"@babel/types": "^7.4.4"
+			}
+		},
+		"@babel/highlight": {
+			"version": "7.0.0",
+			"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+			"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+			"dev": true,
+			"requires": {
+				"chalk": "^2.0.0",
+				"esutils": "^2.0.2",
+				"js-tokens": "^4.0.0"
+			}
+		},
+		"@babel/parser": {
+			"version": "7.4.5",
+			"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz",
+			"integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==",
+			"dev": true
+		},
+		"@babel/plugin-proposal-async-generator-functions": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz",
+			"integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-remap-async-to-generator": "^7.1.0",
+				"@babel/plugin-syntax-async-generators": "^7.2.0"
+			}
+		},
+		"@babel/plugin-proposal-json-strings": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz",
+			"integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/plugin-syntax-json-strings": "^7.2.0"
+			}
+		},
+		"@babel/plugin-proposal-object-rest-spread": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz",
+			"integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/plugin-syntax-object-rest-spread": "^7.2.0"
+			}
+		},
+		"@babel/plugin-proposal-optional-catch-binding": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz",
+			"integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/plugin-syntax-optional-catch-binding": "^7.2.0"
+			}
+		},
+		"@babel/plugin-proposal-unicode-property-regex": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz",
+			"integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-regex": "^7.4.4",
+				"regexpu-core": "^4.5.4"
+			}
+		},
+		"@babel/plugin-syntax-async-generators": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz",
+			"integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-syntax-json-strings": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz",
+			"integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-syntax-object-rest-spread": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz",
+			"integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-syntax-optional-catch-binding": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz",
+			"integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-arrow-functions": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz",
+			"integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-async-to-generator": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz",
+			"integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-imports": "^7.0.0",
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-remap-async-to-generator": "^7.1.0"
+			}
+		},
+		"@babel/plugin-transform-block-scoped-functions": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz",
+			"integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-block-scoping": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz",
+			"integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"lodash": "^4.17.11"
+			}
+		},
+		"@babel/plugin-transform-classes": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz",
+			"integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-annotate-as-pure": "^7.0.0",
+				"@babel/helper-define-map": "^7.4.4",
+				"@babel/helper-function-name": "^7.1.0",
+				"@babel/helper-optimise-call-expression": "^7.0.0",
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-replace-supers": "^7.4.4",
+				"@babel/helper-split-export-declaration": "^7.4.4",
+				"globals": "^11.1.0"
+			}
+		},
+		"@babel/plugin-transform-computed-properties": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz",
+			"integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-destructuring": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz",
+			"integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-dotall-regex": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz",
+			"integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-regex": "^7.4.4",
+				"regexpu-core": "^4.5.4"
+			}
+		},
+		"@babel/plugin-transform-duplicate-keys": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz",
+			"integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-exponentiation-operator": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz",
+			"integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-for-of": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz",
+			"integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-function-name": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz",
+			"integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-function-name": "^7.1.0",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-literals": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz",
+			"integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-member-expression-literals": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz",
+			"integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-modules-amd": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz",
+			"integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-transforms": "^7.1.0",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-modules-commonjs": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz",
+			"integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-transforms": "^7.4.4",
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-simple-access": "^7.1.0"
+			}
+		},
+		"@babel/plugin-transform-modules-systemjs": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz",
+			"integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-hoist-variables": "^7.4.4",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-modules-umd": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz",
+			"integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-transforms": "^7.1.0",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-named-capturing-groups-regex": {
+			"version": "7.4.5",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz",
+			"integrity": "sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==",
+			"dev": true,
+			"requires": {
+				"regexp-tree": "^0.1.6"
+			}
+		},
+		"@babel/plugin-transform-new-target": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz",
+			"integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-object-assign": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.2.0.tgz",
+			"integrity": "sha512-nmE55cZBPFgUktbF2OuoZgPRadfxosLOpSgzEPYotKSls9J4pEPcembi8r78RU37Rph6UApCpNmsQA4QMWK9Ng==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-object-super": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz",
+			"integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-replace-supers": "^7.1.0"
+			}
+		},
+		"@babel/plugin-transform-parameters": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz",
+			"integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-call-delegate": "^7.4.4",
+				"@babel/helper-get-function-arity": "^7.0.0",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-property-literals": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz",
+			"integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-regenerator": {
+			"version": "7.4.5",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz",
+			"integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==",
+			"dev": true,
+			"requires": {
+				"regenerator-transform": "^0.14.0"
+			}
+		},
+		"@babel/plugin-transform-reserved-words": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz",
+			"integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-shorthand-properties": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz",
+			"integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-spread": {
+			"version": "7.2.2",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz",
+			"integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-sticky-regex": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz",
+			"integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-regex": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-template-literals": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz",
+			"integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-annotate-as-pure": "^7.0.0",
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-typeof-symbol": {
+			"version": "7.2.0",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz",
+			"integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0"
+			}
+		},
+		"@babel/plugin-transform-unicode-regex": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz",
+			"integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/helper-regex": "^7.4.4",
+				"regexpu-core": "^4.5.4"
+			}
+		},
+		"@babel/preset-env": {
+			"version": "7.4.5",
+			"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz",
+			"integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-imports": "^7.0.0",
+				"@babel/helper-plugin-utils": "^7.0.0",
+				"@babel/plugin-proposal-async-generator-functions": "^7.2.0",
+				"@babel/plugin-proposal-json-strings": "^7.2.0",
+				"@babel/plugin-proposal-object-rest-spread": "^7.4.4",
+				"@babel/plugin-proposal-optional-catch-binding": "^7.2.0",
+				"@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
+				"@babel/plugin-syntax-async-generators": "^7.2.0",
+				"@babel/plugin-syntax-json-strings": "^7.2.0",
+				"@babel/plugin-syntax-object-rest-spread": "^7.2.0",
+				"@babel/plugin-syntax-optional-catch-binding": "^7.2.0",
+				"@babel/plugin-transform-arrow-functions": "^7.2.0",
+				"@babel/plugin-transform-async-to-generator": "^7.4.4",
+				"@babel/plugin-transform-block-scoped-functions": "^7.2.0",
+				"@babel/plugin-transform-block-scoping": "^7.4.4",
+				"@babel/plugin-transform-classes": "^7.4.4",
+				"@babel/plugin-transform-computed-properties": "^7.2.0",
+				"@babel/plugin-transform-destructuring": "^7.4.4",
+				"@babel/plugin-transform-dotall-regex": "^7.4.4",
+				"@babel/plugin-transform-duplicate-keys": "^7.2.0",
+				"@babel/plugin-transform-exponentiation-operator": "^7.2.0",
+				"@babel/plugin-transform-for-of": "^7.4.4",
+				"@babel/plugin-transform-function-name": "^7.4.4",
+				"@babel/plugin-transform-literals": "^7.2.0",
+				"@babel/plugin-transform-member-expression-literals": "^7.2.0",
+				"@babel/plugin-transform-modules-amd": "^7.2.0",
+				"@babel/plugin-transform-modules-commonjs": "^7.4.4",
+				"@babel/plugin-transform-modules-systemjs": "^7.4.4",
+				"@babel/plugin-transform-modules-umd": "^7.2.0",
+				"@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5",
+				"@babel/plugin-transform-new-target": "^7.4.4",
+				"@babel/plugin-transform-object-super": "^7.2.0",
+				"@babel/plugin-transform-parameters": "^7.4.4",
+				"@babel/plugin-transform-property-literals": "^7.2.0",
+				"@babel/plugin-transform-regenerator": "^7.4.5",
+				"@babel/plugin-transform-reserved-words": "^7.2.0",
+				"@babel/plugin-transform-shorthand-properties": "^7.2.0",
+				"@babel/plugin-transform-spread": "^7.2.0",
+				"@babel/plugin-transform-sticky-regex": "^7.2.0",
+				"@babel/plugin-transform-template-literals": "^7.4.4",
+				"@babel/plugin-transform-typeof-symbol": "^7.2.0",
+				"@babel/plugin-transform-unicode-regex": "^7.4.4",
+				"@babel/types": "^7.4.4",
+				"browserslist": "^4.6.0",
+				"core-js-compat": "^3.1.1",
+				"invariant": "^2.2.2",
+				"js-levenshtein": "^1.1.3",
+				"semver": "^5.5.0"
+			}
+		},
+		"@babel/template": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz",
+			"integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==",
+			"dev": true,
+			"requires": {
+				"@babel/code-frame": "^7.0.0",
+				"@babel/parser": "^7.4.4",
+				"@babel/types": "^7.4.4"
+			}
+		},
+		"@babel/traverse": {
+			"version": "7.4.5",
+			"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz",
+			"integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==",
+			"dev": true,
+			"requires": {
+				"@babel/code-frame": "^7.0.0",
+				"@babel/generator": "^7.4.4",
+				"@babel/helper-function-name": "^7.1.0",
+				"@babel/helper-split-export-declaration": "^7.4.4",
+				"@babel/parser": "^7.4.5",
+				"@babel/types": "^7.4.4",
+				"debug": "^4.1.0",
+				"globals": "^11.1.0",
+				"lodash": "^4.17.11"
+			}
+		},
+		"@babel/types": {
+			"version": "7.4.4",
+			"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz",
+			"integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==",
+			"dev": true,
+			"requires": {
+				"esutils": "^2.0.2",
+				"lodash": "^4.17.11",
+				"to-fast-properties": "^2.0.0"
+			}
+		},
+		"@mrmlnc/readdir-enhanced": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz",
+			"integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==",
+			"dev": true,
+			"requires": {
+				"call-me-maybe": "^1.0.1",
+				"glob-to-regexp": "^0.3.0"
+			}
+		},
+		"@nodelib/fs.stat": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz",
+			"integrity": "sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==",
+			"dev": true
+		},
+		"@types/error-stack-parser": {
+			"version": "1.3.18",
+			"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
+			"integrity": "sha1-4ByfjIXKg7YQMgxiJYsMkCat4Pc=",
+			"dev": true
+		},
+		"@types/estree": {
+			"version": "0.0.39",
+			"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+			"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+			"dev": true
+		},
+		"@types/events": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz",
+			"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
+			"dev": true
+		},
+		"@types/glob": {
+			"version": "7.1.1",
+			"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
+			"integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
+			"dev": true,
+			"requires": {
+				"@types/events": "*",
+				"@types/minimatch": "*",
+				"@types/node": "*"
+			}
+		},
+		"@types/lodash": {
+			"version": "4.14.135",
+			"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.135.tgz",
+			"integrity": "sha512-Ed+tSZ9qM1oYpi5kzdsBuOzcAIn1wDW+e8TFJ50IMJMlSopGdJgKAbhHzN6h1E1OfjlGOr2JepzEWtg9NIfoNg==",
+			"dev": true
+		},
+		"@types/minimatch": {
+			"version": "3.0.3",
+			"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+			"integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+			"dev": true
+		},
+		"@types/node": {
+			"version": "12.0.2",
+			"resolved": "https://registry.npmjs.org/@types/node/-/node-12.0.2.tgz",
+			"integrity": "sha512-5tabW/i+9mhrfEOUcLDu2xBPsHJ+X5Orqy9FKpale3SjDA17j5AEpYq5vfy3oAeAHGcvANRCO3NV3d2D6q3NiA==",
+			"dev": true
+		},
+		"@types/resolve": {
+			"version": "0.0.8",
+			"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
+			"integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
+			"dev": true,
+			"requires": {
+				"@types/node": "*"
+			}
+		},
+		"acorn": {
+			"version": "6.1.1",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.1.1.tgz",
+			"integrity": "sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA==",
+			"dev": true
+		},
+		"acorn-hammerhead": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/acorn-hammerhead/-/acorn-hammerhead-0.2.0.tgz",
+			"integrity": "sha512-kbX1s/0ZikW0WEBY6IrooFgX3AP2D9ycTg0OhxRYLF0Tew/bDK2+8lTxFR4cDdoCZm6Ax8eVf8EV6gbTtr8EYQ==",
+			"dev": true,
+			"requires": {
+				"@types/estree": "^0.0.39"
+			}
+		},
+		"adm-zip": {
+			"version": "0.4.13",
+			"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.13.tgz",
+			"integrity": "sha512-fERNJX8sOXfel6qCBCMPvZLzENBEhZTzKqg6vrOW5pvoEaQuJhRU4ndTAh6lHOxn1I6jnz2NHra56ZODM751uw==",
+			"dev": true
+		},
+		"agent-base": {
+			"version": "4.3.0",
+			"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
+			"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+			"dev": true,
+			"requires": {
+				"es6-promisify": "^5.0.0"
+			}
+		},
+		"ajv": {
+			"version": "6.10.0",
+			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
+			"integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
+			"dev": true,
+			"requires": {
+				"fast-deep-equal": "^2.0.1",
+				"fast-json-stable-stringify": "^2.0.0",
+				"json-schema-traverse": "^0.4.1",
+				"uri-js": "^4.2.2"
+			}
+		},
+		"amdefine": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
+			"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
+			"dev": true
+		},
+		"ansi-escapes": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz",
+			"integrity": "sha1-W65SvkJIeN2Xg+iRDj/Cki6DyBs=",
+			"dev": true
+		},
+		"ansi-regex": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+			"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+			"dev": true
+		},
+		"ansi-styles": {
+			"version": "3.2.1",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+			"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+			"dev": true,
+			"requires": {
+				"color-convert": "^1.9.0"
+			}
+		},
+		"archiver": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz",
+			"integrity": "sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw=",
+			"dev": true,
+			"requires": {
+				"archiver-utils": "^1.3.0",
+				"async": "^2.0.0",
+				"buffer-crc32": "^0.2.1",
+				"glob": "^7.0.0",
+				"lodash": "^4.8.0",
+				"readable-stream": "^2.0.0",
+				"tar-stream": "^1.5.0",
+				"zip-stream": "^1.2.0"
+			},
+			"dependencies": {
+				"async": {
+					"version": "2.6.2",
+					"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
+					"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
+					"dev": true,
+					"requires": {
+						"lodash": "^4.17.11"
+					}
+				}
+			}
+		},
+		"archiver-utils": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz",
+			"integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=",
+			"dev": true,
+			"requires": {
+				"glob": "^7.0.0",
+				"graceful-fs": "^4.1.0",
+				"lazystream": "^1.0.0",
+				"lodash": "^4.8.0",
+				"normalize-path": "^2.0.0",
+				"readable-stream": "^2.0.0"
+			}
+		},
+		"arr-diff": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+			"integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+			"dev": true
+		},
+		"arr-flatten": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+			"integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+			"dev": true
+		},
+		"arr-union": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+			"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+			"dev": true
+		},
+		"array-find": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz",
+			"integrity": "sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=",
+			"dev": true
+		},
+		"array-union": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+			"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+			"dev": true,
+			"requires": {
+				"array-uniq": "^1.0.1"
+			}
+		},
+		"array-uniq": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+			"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+			"dev": true
+		},
+		"array-unique": {
+			"version": "0.3.2",
+			"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+			"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+			"dev": true
+		},
+		"asn1": {
+			"version": "0.2.4",
+			"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+			"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+			"dev": true,
+			"requires": {
+				"safer-buffer": "~2.1.0"
+			}
+		},
+		"assert-plus": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+			"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+			"dev": true
+		},
+		"assertion-error": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+			"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+			"dev": true
+		},
+		"assign-symbols": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+			"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+			"dev": true
+		},
+		"async": {
+			"version": "0.2.6",
+			"resolved": "https://registry.npmjs.org/async/-/async-0.2.6.tgz",
+			"integrity": "sha1-rT83PZJJrjJIgVZVgryQ4VKrvWg=",
+			"dev": true
+		},
+		"async-exit-hook": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-1.1.2.tgz",
+			"integrity": "sha1-gJXXXkiMKazuBVH+hyUhadeJz7o=",
+			"dev": true
+		},
+		"async-limiter": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+			"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
+			"dev": true
+		},
+		"asynckit": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+			"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+			"dev": true
+		},
+		"atob": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+			"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+			"dev": true
+		},
+		"aws-sign2": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+			"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+			"dev": true
+		},
+		"aws4": {
+			"version": "1.8.0",
+			"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+			"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
+			"dev": true
+		},
+		"babel-code-frame": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+			"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+			"dev": true,
+			"requires": {
+				"chalk": "^1.1.3",
+				"esutils": "^2.0.2",
+				"js-tokens": "^3.0.2"
+			},
+			"dependencies": {
+				"ansi-styles": {
+					"version": "2.2.1",
+					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+					"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+					"dev": true
+				},
+				"chalk": {
+					"version": "1.1.3",
+					"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+					"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+					"dev": true,
+					"requires": {
+						"ansi-styles": "^2.2.1",
+						"escape-string-regexp": "^1.0.2",
+						"has-ansi": "^2.0.0",
+						"strip-ansi": "^3.0.0",
+						"supports-color": "^2.0.0"
+					}
+				},
+				"js-tokens": {
+					"version": "3.0.2",
+					"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+					"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+					"dev": true
+				},
+				"supports-color": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+					"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+					"dev": true
+				}
+			}
+		},
+		"babel-core": {
+			"version": "6.26.3",
+			"resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
+			"integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
+			"dev": true,
+			"requires": {
+				"babel-code-frame": "^6.26.0",
+				"babel-generator": "^6.26.0",
+				"babel-helpers": "^6.24.1",
+				"babel-messages": "^6.23.0",
+				"babel-register": "^6.26.0",
+				"babel-runtime": "^6.26.0",
+				"babel-template": "^6.26.0",
+				"babel-traverse": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"babylon": "^6.18.0",
+				"convert-source-map": "^1.5.1",
+				"debug": "^2.6.9",
+				"json5": "^0.5.1",
+				"lodash": "^4.17.4",
+				"minimatch": "^3.0.4",
+				"path-is-absolute": "^1.0.1",
+				"private": "^0.1.8",
+				"slash": "^1.0.0",
+				"source-map": "^0.5.7"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
+				"json5": {
+					"version": "0.5.1",
+					"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+					"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+					"dev": true
+				},
+				"ms": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+					"dev": true
+				}
+			}
+		},
+		"babel-generator": {
+			"version": "6.26.1",
+			"resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+			"integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+			"dev": true,
+			"requires": {
+				"babel-messages": "^6.23.0",
+				"babel-runtime": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"detect-indent": "^4.0.0",
+				"jsesc": "^1.3.0",
+				"lodash": "^4.17.4",
+				"source-map": "^0.5.7",
+				"trim-right": "^1.0.1"
+			},
+			"dependencies": {
+				"jsesc": {
+					"version": "1.3.0",
+					"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+					"integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+					"dev": true
+				}
+			}
+		},
+		"babel-helper-bindify-decorators": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz",
+			"integrity": "sha1-FMGeXxQte0fxmlJDHlKxzLxAozA=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-builder-binary-assignment-operator-visitor": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+			"integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=",
+			"dev": true,
+			"requires": {
+				"babel-helper-explode-assignable-expression": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-call-delegate": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+			"integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
+			"dev": true,
+			"requires": {
+				"babel-helper-hoist-variables": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-define-map": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+			"integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
+			"dev": true,
+			"requires": {
+				"babel-helper-function-name": "^6.24.1",
+				"babel-runtime": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"lodash": "^4.17.4"
+			}
+		},
+		"babel-helper-explode-assignable-expression": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+			"integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-explode-class": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz",
+			"integrity": "sha1-fcKjkQ3uAHBW4eMdZAztPVTqqes=",
+			"dev": true,
+			"requires": {
+				"babel-helper-bindify-decorators": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-function-name": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+			"integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
+			"dev": true,
+			"requires": {
+				"babel-helper-get-function-arity": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-get-function-arity": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+			"integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-hoist-variables": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+			"integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-optimise-call-expression": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+			"integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-regex": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+			"integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"lodash": "^4.17.4"
+			}
+		},
+		"babel-helper-remap-async-to-generator": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+			"integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=",
+			"dev": true,
+			"requires": {
+				"babel-helper-function-name": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helper-replace-supers": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+			"integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
+			"dev": true,
+			"requires": {
+				"babel-helper-optimise-call-expression": "^6.24.1",
+				"babel-messages": "^6.23.0",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-helpers": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+			"integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-messages": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+			"integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-check-es2015-constants": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+			"integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-syntax-async-functions": {
+			"version": "6.13.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+			"integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=",
+			"dev": true
+		},
+		"babel-plugin-syntax-async-generators": {
+			"version": "6.13.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
+			"integrity": "sha1-a8lj67FuzLrmuStZbrfzXDQqi5o=",
+			"dev": true
+		},
+		"babel-plugin-syntax-class-properties": {
+			"version": "6.13.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+			"integrity": "sha1-1+sjt5oxf4VDlixQW4J8fWysJ94=",
+			"dev": true
+		},
+		"babel-plugin-syntax-decorators": {
+			"version": "6.13.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
+			"integrity": "sha1-MSVjtNvePMgGzuPkFszurd0RrAs=",
+			"dev": true
+		},
+		"babel-plugin-syntax-dynamic-import": {
+			"version": "6.18.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
+			"integrity": "sha1-jWomIpyDdFqZgqRBBRVyyqF5sdo=",
+			"dev": true
+		},
+		"babel-plugin-syntax-exponentiation-operator": {
+			"version": "6.13.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+			"integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=",
+			"dev": true
+		},
+		"babel-plugin-syntax-flow": {
+			"version": "6.18.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz",
+			"integrity": "sha1-TDqyCiryaqIM0lmVw5jE63AxDI0=",
+			"dev": true
+		},
+		"babel-plugin-syntax-object-rest-spread": {
+			"version": "6.13.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+			"integrity": "sha1-/WU28rzhODb/o6VFjEkDpZe7O/U=",
+			"dev": true
+		},
+		"babel-plugin-syntax-trailing-function-commas": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+			"integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=",
+			"dev": true
+		},
+		"babel-plugin-transform-async-generator-functions": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
+			"integrity": "sha1-8FiQAUX9PpkHpt3yjaWfIVJYpds=",
+			"dev": true,
+			"requires": {
+				"babel-helper-remap-async-to-generator": "^6.24.1",
+				"babel-plugin-syntax-async-generators": "^6.5.0",
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-async-to-generator": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+			"integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=",
+			"dev": true,
+			"requires": {
+				"babel-helper-remap-async-to-generator": "^6.24.1",
+				"babel-plugin-syntax-async-functions": "^6.8.0",
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-class-properties": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+			"integrity": "sha1-anl2PqYdM9NvN7YRqp3vgagbRqw=",
+			"dev": true,
+			"requires": {
+				"babel-helper-function-name": "^6.24.1",
+				"babel-plugin-syntax-class-properties": "^6.8.0",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-decorators": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz",
+			"integrity": "sha1-eIAT2PjGtSIr33s0Q5Df13Vp4k0=",
+			"dev": true,
+			"requires": {
+				"babel-helper-explode-class": "^6.24.1",
+				"babel-plugin-syntax-decorators": "^6.13.0",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-arrow-functions": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+			"integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-block-scoped-functions": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+			"integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-block-scoping": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+			"integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.26.0",
+				"babel-template": "^6.26.0",
+				"babel-traverse": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"lodash": "^4.17.4"
+			}
+		},
+		"babel-plugin-transform-es2015-classes": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+			"integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
+			"dev": true,
+			"requires": {
+				"babel-helper-define-map": "^6.24.1",
+				"babel-helper-function-name": "^6.24.1",
+				"babel-helper-optimise-call-expression": "^6.24.1",
+				"babel-helper-replace-supers": "^6.24.1",
+				"babel-messages": "^6.23.0",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-computed-properties": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+			"integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-destructuring": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+			"integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-duplicate-keys": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+			"integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-for-of": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+			"integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-function-name": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+			"integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
+			"dev": true,
+			"requires": {
+				"babel-helper-function-name": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-literals": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+			"integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-modules-amd": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+			"integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-modules-commonjs": {
+			"version": "6.26.2",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
+			"integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
+			"dev": true,
+			"requires": {
+				"babel-plugin-transform-strict-mode": "^6.24.1",
+				"babel-runtime": "^6.26.0",
+				"babel-template": "^6.26.0",
+				"babel-types": "^6.26.0"
+			}
+		},
+		"babel-plugin-transform-es2015-modules-systemjs": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+			"integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
+			"dev": true,
+			"requires": {
+				"babel-helper-hoist-variables": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-modules-umd": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+			"integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-object-super": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+			"integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
+			"dev": true,
+			"requires": {
+				"babel-helper-replace-supers": "^6.24.1",
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-parameters": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+			"integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
+			"dev": true,
+			"requires": {
+				"babel-helper-call-delegate": "^6.24.1",
+				"babel-helper-get-function-arity": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-template": "^6.24.1",
+				"babel-traverse": "^6.24.1",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-shorthand-properties": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+			"integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-spread": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+			"integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-sticky-regex": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+			"integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
+			"dev": true,
+			"requires": {
+				"babel-helper-regex": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-plugin-transform-es2015-template-literals": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+			"integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-typeof-symbol": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+			"integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-es2015-unicode-regex": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+			"integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
+			"dev": true,
+			"requires": {
+				"babel-helper-regex": "^6.24.1",
+				"babel-runtime": "^6.22.0",
+				"regexpu-core": "^2.0.0"
+			},
+			"dependencies": {
+				"jsesc": {
+					"version": "0.5.0",
+					"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+					"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+					"dev": true
+				},
+				"regexpu-core": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
+					"integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
+					"dev": true,
+					"requires": {
+						"regenerate": "^1.2.1",
+						"regjsgen": "^0.2.0",
+						"regjsparser": "^0.1.4"
+					}
+				},
+				"regjsgen": {
+					"version": "0.2.0",
+					"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+					"integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
+					"dev": true
+				},
+				"regjsparser": {
+					"version": "0.1.5",
+					"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+					"integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
+					"dev": true,
+					"requires": {
+						"jsesc": "~0.5.0"
+					}
+				}
+			}
+		},
+		"babel-plugin-transform-exponentiation-operator": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+			"integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=",
+			"dev": true,
+			"requires": {
+				"babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
+				"babel-plugin-syntax-exponentiation-operator": "^6.8.0",
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-flow-strip-types": {
+			"version": "6.22.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz",
+			"integrity": "sha1-hMtnKTXUNxT9wyvOhFaNh0Qc988=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-syntax-flow": "^6.18.0",
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-for-of-as-array": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-for-of-as-array/-/babel-plugin-transform-for-of-as-array-1.1.1.tgz",
+			"integrity": "sha512-eE4hZJhOUKpX0q/X3adR8B4hLox+t8oe4ZqmhANUmv4cds07AbWt6O0rtFXK7PKFPPnW4nz/5mpbkPMkflyGeg==",
+			"dev": true
+		},
+		"babel-plugin-transform-object-rest-spread": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+			"integrity": "sha1-DzZpLVD+9rfi1LOsFHgTepY7ewY=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-syntax-object-rest-spread": "^6.8.0",
+				"babel-runtime": "^6.26.0"
+			}
+		},
+		"babel-plugin-transform-regenerator": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+			"integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
+			"dev": true,
+			"requires": {
+				"regenerator-transform": "^0.10.0"
+			},
+			"dependencies": {
+				"regenerator-transform": {
+					"version": "0.10.1",
+					"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+					"integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+					"dev": true,
+					"requires": {
+						"babel-runtime": "^6.18.0",
+						"babel-types": "^6.19.0",
+						"private": "^0.1.6"
+					}
+				}
+			}
+		},
+		"babel-plugin-transform-runtime": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
+			"integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0"
+			}
+		},
+		"babel-plugin-transform-strict-mode": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+			"integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.22.0",
+				"babel-types": "^6.24.1"
+			}
+		},
+		"babel-preset-env": {
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.7.0.tgz",
+			"integrity": "sha512-9OR2afuKDneX2/q2EurSftUYM0xGu4O2D9adAhVfADDhrYDaxXV0rBbevVYoY9n6nyX1PmQW/0jtpJvUNr9CHg==",
+			"dev": true,
+			"requires": {
+				"babel-plugin-check-es2015-constants": "^6.22.0",
+				"babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+				"babel-plugin-transform-async-to-generator": "^6.22.0",
+				"babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
+				"babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
+				"babel-plugin-transform-es2015-block-scoping": "^6.23.0",
+				"babel-plugin-transform-es2015-classes": "^6.23.0",
+				"babel-plugin-transform-es2015-computed-properties": "^6.22.0",
+				"babel-plugin-transform-es2015-destructuring": "^6.23.0",
+				"babel-plugin-transform-es2015-duplicate-keys": "^6.22.0",
+				"babel-plugin-transform-es2015-for-of": "^6.23.0",
+				"babel-plugin-transform-es2015-function-name": "^6.22.0",
+				"babel-plugin-transform-es2015-literals": "^6.22.0",
+				"babel-plugin-transform-es2015-modules-amd": "^6.22.0",
+				"babel-plugin-transform-es2015-modules-commonjs": "^6.23.0",
+				"babel-plugin-transform-es2015-modules-systemjs": "^6.23.0",
+				"babel-plugin-transform-es2015-modules-umd": "^6.23.0",
+				"babel-plugin-transform-es2015-object-super": "^6.22.0",
+				"babel-plugin-transform-es2015-parameters": "^6.23.0",
+				"babel-plugin-transform-es2015-shorthand-properties": "^6.22.0",
+				"babel-plugin-transform-es2015-spread": "^6.22.0",
+				"babel-plugin-transform-es2015-sticky-regex": "^6.22.0",
+				"babel-plugin-transform-es2015-template-literals": "^6.22.0",
+				"babel-plugin-transform-es2015-typeof-symbol": "^6.23.0",
+				"babel-plugin-transform-es2015-unicode-regex": "^6.22.0",
+				"babel-plugin-transform-exponentiation-operator": "^6.22.0",
+				"babel-plugin-transform-regenerator": "^6.22.0",
+				"browserslist": "^3.2.6",
+				"invariant": "^2.2.2",
+				"semver": "^5.3.0"
+			},
+			"dependencies": {
+				"browserslist": {
+					"version": "3.2.8",
+					"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-3.2.8.tgz",
+					"integrity": "sha512-WHVocJYavUwVgVViC0ORikPHQquXwVh939TaelZ4WDqpWgTX/FsGhl/+P4qBUAGcRvtOgDgC+xftNWWp2RUTAQ==",
+					"dev": true,
+					"requires": {
+						"caniuse-lite": "^1.0.30000844",
+						"electron-to-chromium": "^1.3.47"
+					}
+				}
+			}
+		},
+		"babel-preset-flow": {
+			"version": "6.23.0",
+			"resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz",
+			"integrity": "sha1-5xIYiHCFrpoktb5Baa/7WZgWxJ0=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-transform-flow-strip-types": "^6.22.0"
+			}
+		},
+		"babel-preset-stage-2": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz",
+			"integrity": "sha1-2eKWD7PXEYfw5k7sYrwHdnIZvcE=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-syntax-dynamic-import": "^6.18.0",
+				"babel-plugin-transform-class-properties": "^6.24.1",
+				"babel-plugin-transform-decorators": "^6.24.1",
+				"babel-preset-stage-3": "^6.24.1"
+			}
+		},
+		"babel-preset-stage-3": {
+			"version": "6.24.1",
+			"resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
+			"integrity": "sha1-g2raCp56f6N8sTj7kyb4eTSkg5U=",
+			"dev": true,
+			"requires": {
+				"babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+				"babel-plugin-transform-async-generator-functions": "^6.24.1",
+				"babel-plugin-transform-async-to-generator": "^6.24.1",
+				"babel-plugin-transform-exponentiation-operator": "^6.24.1",
+				"babel-plugin-transform-object-rest-spread": "^6.22.0"
+			}
+		},
+		"babel-register": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+			"integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+			"dev": true,
+			"requires": {
+				"babel-core": "^6.26.0",
+				"babel-runtime": "^6.26.0",
+				"core-js": "^2.5.0",
+				"home-or-tmp": "^2.0.0",
+				"lodash": "^4.17.4",
+				"mkdirp": "^0.5.1",
+				"source-map-support": "^0.4.15"
+			},
+			"dependencies": {
+				"source-map-support": {
+					"version": "0.4.18",
+					"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+					"integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+					"dev": true,
+					"requires": {
+						"source-map": "^0.5.6"
+					}
+				}
+			}
+		},
+		"babel-runtime": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+			"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+			"dev": true,
+			"requires": {
+				"core-js": "^2.4.0",
+				"regenerator-runtime": "^0.11.0"
+			}
+		},
+		"babel-template": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+			"integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.26.0",
+				"babel-traverse": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"babylon": "^6.18.0",
+				"lodash": "^4.17.4"
+			}
+		},
+		"babel-traverse": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+			"integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+			"dev": true,
+			"requires": {
+				"babel-code-frame": "^6.26.0",
+				"babel-messages": "^6.23.0",
+				"babel-runtime": "^6.26.0",
+				"babel-types": "^6.26.0",
+				"babylon": "^6.18.0",
+				"debug": "^2.6.8",
+				"globals": "^9.18.0",
+				"invariant": "^2.2.2",
+				"lodash": "^4.17.4"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
+				"globals": {
+					"version": "9.18.0",
+					"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+					"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+					"dev": true
+				},
+				"ms": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+					"dev": true
+				}
+			}
+		},
+		"babel-types": {
+			"version": "6.26.0",
+			"resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+			"integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.26.0",
+				"esutils": "^2.0.2",
+				"lodash": "^4.17.4",
+				"to-fast-properties": "^1.0.3"
+			},
+			"dependencies": {
+				"to-fast-properties": {
+					"version": "1.0.3",
+					"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+					"integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+					"dev": true
+				}
+			}
+		},
+		"babylon": {
+			"version": "6.18.0",
+			"resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+			"integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+			"dev": true
+		},
+		"balanced-match": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+			"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
+			"dev": true
+		},
+		"base": {
+			"version": "0.11.2",
+			"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+			"integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+			"dev": true,
+			"requires": {
+				"cache-base": "^1.0.1",
+				"class-utils": "^0.3.5",
+				"component-emitter": "^1.2.1",
+				"define-property": "^1.0.0",
+				"isobject": "^3.0.1",
+				"mixin-deep": "^1.2.0",
+				"pascalcase": "^0.1.1"
+			},
+			"dependencies": {
+				"define-property": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+					"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^1.0.0"
+					}
+				},
+				"is-accessor-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+					"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-data-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+					"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-descriptor": {
+					"version": "1.0.2",
+					"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+					"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+					"dev": true,
+					"requires": {
+						"is-accessor-descriptor": "^1.0.0",
+						"is-data-descriptor": "^1.0.0",
+						"kind-of": "^6.0.2"
+					}
+				}
+			}
+		},
+		"base64-js": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
+			"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
+			"dev": true
+		},
+		"bcrypt-pbkdf": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+			"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+			"dev": true,
+			"requires": {
+				"tweetnacl": "^0.14.3"
+			}
+		},
+		"bin-v8-flags-filter": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/bin-v8-flags-filter/-/bin-v8-flags-filter-1.2.0.tgz",
+			"integrity": "sha512-g8aeYkY7GhyyKRvQMBsJQZjhm2iCX3dKYvfrMpwVR8IxmUGrkpCBFoKbB9Rh0o3sTLCjU/1tFpZ4C7j3f+D+3g==",
+			"dev": true
+		},
+		"bl": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
+			"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
+			"dev": true,
+			"requires": {
+				"readable-stream": "^2.3.5",
+				"safe-buffer": "^5.1.1"
+			}
+		},
+		"bowser": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/bowser/-/bowser-1.6.0.tgz",
+			"integrity": "sha1-N/w4e2Fstq7zcNq01r1AK3TFxU0=",
+			"dev": true
+		},
+		"brace-expansion": {
+			"version": "1.1.11",
+			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+			"dev": true,
+			"requires": {
+				"balanced-match": "^1.0.0",
+				"concat-map": "0.0.1"
+			}
+		},
+		"braces": {
+			"version": "2.3.2",
+			"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+			"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+			"dev": true,
+			"requires": {
+				"arr-flatten": "^1.1.0",
+				"array-unique": "^0.3.2",
+				"extend-shallow": "^2.0.1",
+				"fill-range": "^4.0.0",
+				"isobject": "^3.0.1",
+				"repeat-element": "^1.1.2",
+				"snapdragon": "^0.8.1",
+				"snapdragon-node": "^2.0.1",
+				"split-string": "^3.0.2",
+				"to-regex": "^3.0.1"
+			},
+			"dependencies": {
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				}
+			}
+		},
+		"brotli": {
+			"version": "1.3.2",
+			"resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.2.tgz",
+			"integrity": "sha1-UlqcrU/LqWR119OI9q7LE+7VL0Y=",
+			"dev": true,
+			"requires": {
+				"base64-js": "^1.1.2"
+			}
+		},
+		"browserslist": {
+			"version": "4.6.0",
+			"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.0.tgz",
+			"integrity": "sha512-Jk0YFwXBuMOOol8n6FhgkDzn3mY9PYLYGk29zybF05SbRTsMgPqmTNeQQhOghCxq5oFqAXE3u4sYddr4C0uRhg==",
+			"dev": true,
+			"requires": {
+				"caniuse-lite": "^1.0.30000967",
+				"electron-to-chromium": "^1.3.133",
+				"node-releases": "^1.1.19"
+			}
+		},
+		"buffer": {
+			"version": "5.2.1",
+			"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz",
+			"integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==",
+			"dev": true,
+			"requires": {
+				"base64-js": "^1.0.2",
+				"ieee754": "^1.1.4"
+			}
+		},
+		"buffer-alloc": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
+			"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
+			"dev": true,
+			"requires": {
+				"buffer-alloc-unsafe": "^1.1.0",
+				"buffer-fill": "^1.0.0"
+			}
+		},
+		"buffer-alloc-unsafe": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
+			"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
+			"dev": true
+		},
+		"buffer-crc32": {
+			"version": "0.2.13",
+			"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+			"integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+			"dev": true
+		},
+		"buffer-fill": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz",
+			"integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=",
+			"dev": true
+		},
+		"buffer-from": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+			"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+			"dev": true
+		},
+		"builtin-modules": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
+			"integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
+			"dev": true
+		},
+		"cache-base": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+			"integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+			"dev": true,
+			"requires": {
+				"collection-visit": "^1.0.0",
+				"component-emitter": "^1.2.1",
+				"get-value": "^2.0.6",
+				"has-value": "^1.0.0",
+				"isobject": "^3.0.1",
+				"set-value": "^2.0.0",
+				"to-object-path": "^0.3.0",
+				"union-value": "^1.0.0",
+				"unset-value": "^1.0.0"
+			}
+		},
+		"call-me-maybe": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
+			"integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=",
+			"dev": true
+		},
+		"callsite": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+			"integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+			"dev": true
+		},
+		"callsite-record": {
+			"version": "4.1.3",
+			"resolved": "https://registry.npmjs.org/callsite-record/-/callsite-record-4.1.3.tgz",
+			"integrity": "sha512-otAcPmu8TiHZ38cIL3NjQa1nGoSQRRe8WDDUgj5ZUwJWn1wzOYBwVSJbpVyzZ0sesQeKlYsPu9DG70fhh6AK9g==",
+			"dev": true,
+			"requires": {
+				"@types/error-stack-parser": "^1.3.18",
+				"@types/lodash": "^4.14.72",
+				"callsite": "^1.0.0",
+				"chalk": "^2.4.0",
+				"error-stack-parser": "^1.3.3",
+				"highlight-es": "^1.0.0",
+				"lodash": "4.6.1 || ^4.16.1",
+				"pinkie-promise": "^2.0.0"
+			}
+		},
+		"caniuse-lite": {
+			"version": "1.0.30000971",
+			"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000971.tgz",
+			"integrity": "sha512-TQFYFhRS0O5rdsmSbF1Wn+16latXYsQJat66f7S7lizXW1PVpWJeZw9wqqVLIjuxDRz7s7xRUj13QCfd8hKn6g==",
+			"dev": true
+		},
+		"caseless": {
+			"version": "0.12.0",
+			"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+			"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+			"dev": true
+		},
+		"chai": {
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
+			"integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
+			"dev": true,
+			"requires": {
+				"assertion-error": "^1.1.0",
+				"check-error": "^1.0.2",
+				"deep-eql": "^3.0.1",
+				"get-func-name": "^2.0.0",
+				"pathval": "^1.1.0",
+				"type-detect": "^4.0.5"
+			}
+		},
+		"chalk": {
+			"version": "2.4.2",
+			"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+			"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+			"dev": true,
+			"requires": {
+				"ansi-styles": "^3.2.1",
+				"escape-string-regexp": "^1.0.5",
+				"supports-color": "^5.3.0"
+			}
+		},
+		"check-error": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+			"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=",
+			"dev": true
+		},
+		"chrome-emulated-devices-list": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/chrome-emulated-devices-list/-/chrome-emulated-devices-list-0.1.1.tgz",
+			"integrity": "sha512-wQu6YKNTNGaUXovpkvXLnfeumVK47r2TKpOuCTwOKv/5SmRzfHual+E+oDIwS3KFWAcJPAhoNRAOLvXwzC6/pw==",
+			"dev": true
+		},
+		"chrome-remote-interface": {
+			"version": "0.25.7",
+			"resolved": "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.25.7.tgz",
+			"integrity": "sha512-6zI6LbR2IiGmduFZededaerEr9hHXabxT/L+fRrdq65a0CfyLMzpq0BKuZiqN0Upqcacsb6q2POj7fmobwBsEA==",
+			"dev": true,
+			"requires": {
+				"commander": "2.11.x",
+				"ws": "3.3.x"
+			},
+			"dependencies": {
+				"commander": {
+					"version": "2.11.0",
+					"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
+					"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
+					"dev": true
+				}
+			}
+		},
+		"ci-info": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
+			"integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
+			"dev": true
+		},
+		"class-utils": {
+			"version": "0.3.6",
+			"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+			"integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+			"dev": true,
+			"requires": {
+				"arr-union": "^3.1.0",
+				"define-property": "^0.2.5",
+				"isobject": "^3.0.0",
+				"static-extend": "^0.1.1"
+			},
+			"dependencies": {
+				"define-property": {
+					"version": "0.2.5",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+					"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^0.1.0"
+					}
+				}
+			}
+		},
+		"code-point-at": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+			"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+			"dev": true
+		},
+		"coffeescript": {
+			"version": "2.4.1",
+			"resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.4.1.tgz",
+			"integrity": "sha512-34GV1aHrsMpTaO3KfMJL40ZNuvKDR/g98THHnE9bQj8HjMaZvSrLik99WWqyMhRtbe8V5hpx5iLgdcSvM/S2wg==",
+			"dev": true
+		},
+		"collection-visit": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+			"integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+			"dev": true,
+			"requires": {
+				"map-visit": "^1.0.0",
+				"object-visit": "^1.0.0"
+			}
+		},
+		"color-convert": {
+			"version": "1.9.3",
+			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+			"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+			"dev": true,
+			"requires": {
+				"color-name": "1.1.3"
+			}
+		},
+		"color-name": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+			"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+			"dev": true
+		},
+		"combined-stream": {
+			"version": "1.0.8",
+			"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+			"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+			"dev": true,
+			"requires": {
+				"delayed-stream": "~1.0.0"
+			}
+		},
+		"commander": {
+			"version": "2.20.0",
+			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+			"integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
+			"dev": true
+		},
+		"component-emitter": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+			"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+			"dev": true
+		},
+		"compress-commons": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz",
+			"integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=",
+			"dev": true,
+			"requires": {
+				"buffer-crc32": "^0.2.1",
+				"crc32-stream": "^2.0.0",
+				"normalize-path": "^2.0.0",
+				"readable-stream": "^2.0.0"
+			}
+		},
+		"concat-map": {
+			"version": "0.0.1",
+			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+			"dev": true
+		},
+		"convert-source-map": {
+			"version": "1.6.0",
+			"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
+			"integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
+			"dev": true,
+			"requires": {
+				"safe-buffer": "~5.1.1"
+			}
+		},
+		"copy-descriptor": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+			"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+			"dev": true
+		},
+		"core-js": {
+			"version": "2.6.9",
+			"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
+			"integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==",
+			"dev": true
+		},
+		"core-js-compat": {
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.1.2.tgz",
+			"integrity": "sha512-X0Ch5f6itrHxhg5HSJucX6nNLNAGr+jq+biBh6nPGc3YAWz2a8p/ZIZY8cUkDzSRNG54omAuu3hoEF8qZbu/6Q==",
+			"dev": true,
+			"requires": {
+				"browserslist": "^4.6.0",
+				"core-js-pure": "3.1.2",
+				"semver": "^6.0.0"
+			},
+			"dependencies": {
+				"semver": {
+					"version": "6.1.0",
+					"resolved": "https://registry.npmjs.org/semver/-/semver-6.1.0.tgz",
+					"integrity": "sha512-kCqEOOHoBcFs/2Ccuk4Xarm/KiWRSLEX9CAZF8xkJ6ZPlIoTZ8V5f7J16vYLJqDbR7KrxTJpR2lqjIEm2Qx9cQ==",
+					"dev": true
+				}
+			}
+		},
+		"core-js-pure": {
+			"version": "3.1.2",
+			"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.1.2.tgz",
+			"integrity": "sha512-5ckIdBF26B3ldK9PM177y2ZcATP2oweam9RskHSoqfZCrJ2As6wVg8zJ1zTriFsZf6clj/N1ThDFRGaomMsh9w==",
+			"dev": true
+		},
+		"core-util-is": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+			"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+			"dev": true
+		},
+		"crc": {
+			"version": "3.8.0",
+			"resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
+			"integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
+			"dev": true,
+			"requires": {
+				"buffer": "^5.1.0"
+			}
+		},
+		"crc32-stream": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz",
+			"integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=",
+			"dev": true,
+			"requires": {
+				"crc": "^3.4.4",
+				"readable-stream": "^2.0.0"
+			}
+		},
+		"crypto-md5": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/crypto-md5/-/crypto-md5-1.0.0.tgz",
+			"integrity": "sha1-zMjadQx1PH7curxUKWdHKjhOhrs=",
+			"dev": true
+		},
+		"css": {
+			"version": "2.2.3",
+			"resolved": "https://registry.npmjs.org/css/-/css-2.2.3.tgz",
+			"integrity": "sha512-0W171WccAjQGGTKLhw4m2nnl0zPHUlTO/I8td4XzJgIB8Hg3ZZx71qT4G4eX8OVsSiaAKiUMy73E3nsbPlg2DQ==",
+			"dev": true,
+			"requires": {
+				"inherits": "^2.0.1",
+				"source-map": "^0.1.38",
+				"source-map-resolve": "^0.5.1",
+				"urix": "^0.1.0"
+			},
+			"dependencies": {
+				"source-map": {
+					"version": "0.1.43",
+					"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
+					"integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
+					"dev": true,
+					"requires": {
+						"amdefine": ">=0.0.4"
+					}
+				}
+			}
+		},
+		"dashdash": {
+			"version": "1.14.1",
+			"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+			"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+			"dev": true,
+			"requires": {
+				"assert-plus": "^1.0.0"
+			}
+		},
+		"debug": {
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+			"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
+			"dev": true,
+			"requires": {
+				"ms": "^2.1.1"
+			}
+		},
+		"decode-uri-component": {
+			"version": "0.2.0",
+			"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+			"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+			"dev": true
+		},
+		"dedent": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.4.0.tgz",
+			"integrity": "sha1-h979BAvUwVldljKC7FfzwqhSVkI=",
+			"dev": true
+		},
+		"deep-eql": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
+			"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
+			"dev": true,
+			"requires": {
+				"type-detect": "^4.0.0"
+			}
+		},
+		"define-property": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+			"integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+			"dev": true,
+			"requires": {
+				"is-descriptor": "^1.0.2",
+				"isobject": "^3.0.1"
+			},
+			"dependencies": {
+				"is-accessor-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+					"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-data-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+					"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-descriptor": {
+					"version": "1.0.2",
+					"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+					"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+					"dev": true,
+					"requires": {
+						"is-accessor-descriptor": "^1.0.0",
+						"is-data-descriptor": "^1.0.0",
+						"kind-of": "^6.0.2"
+					}
+				}
+			}
+		},
+		"del": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz",
+			"integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=",
+			"dev": true,
+			"requires": {
+				"globby": "^6.1.0",
+				"is-path-cwd": "^1.0.0",
+				"is-path-in-cwd": "^1.0.0",
+				"p-map": "^1.1.1",
+				"pify": "^3.0.0",
+				"rimraf": "^2.2.8"
+			},
+			"dependencies": {
+				"globby": {
+					"version": "6.1.0",
+					"resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
+					"integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
+					"dev": true,
+					"requires": {
+						"array-union": "^1.0.1",
+						"glob": "^7.0.3",
+						"object-assign": "^4.0.1",
+						"pify": "^2.0.0",
+						"pinkie-promise": "^2.0.0"
+					},
+					"dependencies": {
+						"pify": {
+							"version": "2.3.0",
+							"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+							"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+							"dev": true
+						}
+					}
+				},
+				"pify": {
+					"version": "3.0.0",
+					"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+					"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+					"dev": true
+				}
+			}
+		},
+		"delayed-stream": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+			"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+			"dev": true
+		},
+		"desired-capabilities": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/desired-capabilities/-/desired-capabilities-0.1.0.tgz",
+			"integrity": "sha1-84YNEu3g2sgZpHzJWaaMULqbqD4=",
+			"dev": true,
+			"requires": {
+				"extend": "^3.0.0"
+			}
+		},
+		"detect-indent": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+			"integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+			"dev": true,
+			"requires": {
+				"repeating": "^2.0.0"
+			}
+		},
+		"dir-glob": {
+			"version": "2.2.2",
+			"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",
+			"integrity": "sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==",
+			"dev": true,
+			"requires": {
+				"path-type": "^3.0.0"
+			}
+		},
+		"ecc-jsbn": {
+			"version": "0.1.2",
+			"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+			"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+			"dev": true,
+			"requires": {
+				"jsbn": "~0.1.0",
+				"safer-buffer": "^2.1.0"
+			}
+		},
+		"electron-to-chromium": {
+			"version": "1.3.137",
+			"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.137.tgz",
+			"integrity": "sha512-kGi32g42a8vS/WnYE7ELJyejRT7hbr3UeOOu0WeuYuQ29gCpg9Lrf6RdcTQVXSt/v0bjCfnlb/EWOOsiKpTmkw==",
+			"dev": true
+		},
+		"elegant-spinner": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz",
+			"integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=",
+			"dev": true
+		},
+		"emittery": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz",
+			"integrity": "sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ==",
+			"dev": true
+		},
+		"end-of-stream": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+			"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+			"dev": true,
+			"requires": {
+				"once": "^1.4.0"
+			}
+		},
+		"endpoint-utils": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/endpoint-utils/-/endpoint-utils-1.0.2.tgz",
+			"integrity": "sha1-CAjDNppyfNeWejn/NOvJJriBRqg=",
+			"dev": true,
+			"requires": {
+				"ip": "^1.1.3",
+				"pinkie-promise": "^1.0.0"
+			},
+			"dependencies": {
+				"pinkie": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz",
+					"integrity": "sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=",
+					"dev": true
+				},
+				"pinkie-promise": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
+					"integrity": "sha1-0dpn9UglY7t89X8oauKCLs+/NnA=",
+					"dev": true,
+					"requires": {
+						"pinkie": "^1.0.0"
+					}
+				}
+			}
+		},
+		"error-stack-parser": {
+			"version": "1.3.6",
+			"resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-1.3.6.tgz",
+			"integrity": "sha1-4Oc7k+QXE40c18C3RrGkoUhUwpI=",
+			"dev": true,
+			"requires": {
+				"stackframe": "^0.3.1"
+			}
+		},
+		"es6-promise": {
+			"version": "4.2.8",
+			"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+			"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+			"dev": true
+		},
+		"es6-promisify": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
+			"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+			"dev": true,
+			"requires": {
+				"es6-promise": "^4.0.3"
+			}
+		},
+		"escape-string-regexp": {
+			"version": "1.0.5",
+			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+			"dev": true
+		},
+		"esotope-hammerhead": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/esotope-hammerhead/-/esotope-hammerhead-0.2.1.tgz",
+			"integrity": "sha512-IicdvCt1BIFTIM4nbjxGp98whIakOYZ4lA0UaDXnXpJpB11jYBX11Uv3x2f5ncSlFmxyZRdrN5skH5wK4TCWFQ==",
+			"dev": true,
+			"requires": {
+				"@types/estree": "^0.0.39"
+			}
+		},
+		"estree-walker": {
+			"version": "0.6.0",
+			"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.0.tgz",
+			"integrity": "sha512-peq1RfVAVzr3PU/jL31RaOjUKLoZJpObQWJJ+LgfcxDUifyLZ1RjPQZTl0pzj2uJ45b7A7XpyppXvxdEqzo4rw==",
+			"dev": true
+		},
+		"esutils": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+			"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+			"dev": true
+		},
+		"expand-brackets": {
+			"version": "2.1.4",
+			"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+			"integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+			"dev": true,
+			"requires": {
+				"debug": "^2.3.3",
+				"define-property": "^0.2.5",
+				"extend-shallow": "^2.0.1",
+				"posix-character-classes": "^0.1.0",
+				"regex-not": "^1.0.0",
+				"snapdragon": "^0.8.1",
+				"to-regex": "^3.0.1"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
+				"define-property": {
+					"version": "0.2.5",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+					"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^0.1.0"
+					}
+				},
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				},
+				"ms": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+					"dev": true
+				}
+			}
+		},
+		"extend": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+			"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+			"dev": true
+		},
+		"extend-shallow": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+			"integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+			"dev": true,
+			"requires": {
+				"assign-symbols": "^1.0.0",
+				"is-extendable": "^1.0.1"
+			},
+			"dependencies": {
+				"is-extendable": {
+					"version": "1.0.1",
+					"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+					"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+					"dev": true,
+					"requires": {
+						"is-plain-object": "^2.0.4"
+					}
+				}
+			}
+		},
+		"extglob": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+			"integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+			"dev": true,
+			"requires": {
+				"array-unique": "^0.3.2",
+				"define-property": "^1.0.0",
+				"expand-brackets": "^2.1.4",
+				"extend-shallow": "^2.0.1",
+				"fragment-cache": "^0.2.1",
+				"regex-not": "^1.0.0",
+				"snapdragon": "^0.8.1",
+				"to-regex": "^3.0.1"
+			},
+			"dependencies": {
+				"define-property": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+					"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^1.0.0"
+					}
+				},
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				},
+				"is-accessor-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+					"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-data-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+					"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-descriptor": {
+					"version": "1.0.2",
+					"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+					"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+					"dev": true,
+					"requires": {
+						"is-accessor-descriptor": "^1.0.0",
+						"is-data-descriptor": "^1.0.0",
+						"kind-of": "^6.0.2"
+					}
+				}
+			}
+		},
+		"extsprintf": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+			"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+			"dev": true
+		},
+		"fast-deep-equal": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+			"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+			"dev": true
+		},
+		"fast-glob": {
+			"version": "2.2.7",
+			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
+			"integrity": "sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==",
+			"dev": true,
+			"requires": {
+				"@mrmlnc/readdir-enhanced": "^2.2.1",
+				"@nodelib/fs.stat": "^1.1.2",
+				"glob-parent": "^3.1.0",
+				"is-glob": "^4.0.0",
+				"merge2": "^1.2.3",
+				"micromatch": "^3.1.10"
+			},
+			"dependencies": {
+				"is-glob": {
+					"version": "4.0.1",
+					"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+					"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+					"dev": true,
+					"requires": {
+						"is-extglob": "^2.1.1"
+					}
+				}
+			}
+		},
+		"fast-json-stable-stringify": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+			"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=",
+			"dev": true
+		},
+		"fill-range": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+			"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+			"dev": true,
+			"requires": {
+				"extend-shallow": "^2.0.1",
+				"is-number": "^3.0.0",
+				"repeat-string": "^1.6.1",
+				"to-regex-range": "^2.1.0"
+			},
+			"dependencies": {
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				}
+			}
+		},
+		"for-in": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+			"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+			"dev": true
+		},
+		"forever-agent": {
+			"version": "0.6.1",
+			"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+			"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+			"dev": true
+		},
+		"form-data": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+			"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+			"dev": true,
+			"requires": {
+				"asynckit": "^0.4.0",
+				"combined-stream": "^1.0.6",
+				"mime-types": "^2.1.12"
+			}
+		},
+		"fragment-cache": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+			"integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+			"dev": true,
+			"requires": {
+				"map-cache": "^0.2.2"
+			}
+		},
+		"fs-constants": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+			"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+			"dev": true
+		},
+		"fs.realpath": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+			"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+			"dev": true
+		},
+		"get-func-name": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+			"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=",
+			"dev": true
+		},
+		"get-stdin": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
+			"integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
+			"dev": true
+		},
+		"get-value": {
+			"version": "2.0.6",
+			"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+			"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+			"dev": true
+		},
+		"getpass": {
+			"version": "0.1.7",
+			"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+			"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+			"dev": true,
+			"requires": {
+				"assert-plus": "^1.0.0"
+			}
+		},
+		"glob": {
+			"version": "7.1.4",
+			"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
+			"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
+			"dev": true,
+			"requires": {
+				"fs.realpath": "^1.0.0",
+				"inflight": "^1.0.4",
+				"inherits": "2",
+				"minimatch": "^3.0.4",
+				"once": "^1.3.0",
+				"path-is-absolute": "^1.0.0"
+			}
+		},
+		"glob-parent": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+			"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+			"dev": true,
+			"requires": {
+				"is-glob": "^3.1.0",
+				"path-dirname": "^1.0.0"
+			},
+			"dependencies": {
+				"is-glob": {
+					"version": "3.1.0",
+					"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+					"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+					"dev": true,
+					"requires": {
+						"is-extglob": "^2.1.0"
+					}
+				}
+			}
+		},
+		"glob-to-regexp": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
+			"integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=",
+			"dev": true
+		},
+		"globals": {
+			"version": "11.12.0",
+			"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+			"integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+			"dev": true
+		},
+		"globby": {
+			"version": "9.2.0",
+			"resolved": "https://registry.npmjs.org/globby/-/globby-9.2.0.tgz",
+			"integrity": "sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==",
+			"dev": true,
+			"requires": {
+				"@types/glob": "^7.1.1",
+				"array-union": "^1.0.2",
+				"dir-glob": "^2.2.2",
+				"fast-glob": "^2.2.6",
+				"glob": "^7.1.3",
+				"ignore": "^4.0.3",
+				"pify": "^4.0.1",
+				"slash": "^2.0.0"
+			},
+			"dependencies": {
+				"pify": {
+					"version": "4.0.1",
+					"resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+					"integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+					"dev": true
+				},
+				"slash": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
+					"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
+					"dev": true
+				}
+			}
+		},
+		"graceful-fs": {
+			"version": "4.2.0",
+			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
+			"integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==",
+			"dev": true
+		},
+		"graphlib": {
+			"version": "2.1.7",
+			"resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.7.tgz",
+			"integrity": "sha512-TyI9jIy2J4j0qgPmOOrHTCtpPqJGN/aurBwc6ZT+bRii+di1I+Wv3obRhVrmBEXet+qkMaEX67dXrwsd3QQM6w==",
+			"dev": true,
+			"requires": {
+				"lodash": "^4.17.5"
+			}
+		},
+		"har-schema": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+			"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+			"dev": true
+		},
+		"har-validator": {
+			"version": "5.1.3",
+			"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
+			"integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+			"dev": true,
+			"requires": {
+				"ajv": "^6.5.5",
+				"har-schema": "^2.0.0"
+			}
+		},
+		"has-ansi": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+			"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+			"dev": true,
+			"requires": {
+				"ansi-regex": "^2.0.0"
+			}
+		},
+		"has-flag": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+			"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+			"dev": true
+		},
+		"has-value": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+			"integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+			"dev": true,
+			"requires": {
+				"get-value": "^2.0.6",
+				"has-values": "^1.0.0",
+				"isobject": "^3.0.0"
+			}
+		},
+		"has-values": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+			"integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+			"dev": true,
+			"requires": {
+				"is-number": "^3.0.0",
+				"kind-of": "^4.0.0"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "4.0.0",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+					"integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"highlight-es": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/highlight-es/-/highlight-es-1.0.3.tgz",
+			"integrity": "sha512-s/SIX6yp/5S1p8aC/NRDC1fwEb+myGIfp8/TzZz0rtAv8fzsdX7vGl3Q1TrXCsczFq8DI3CBFBCySPClfBSdbg==",
+			"dev": true,
+			"requires": {
+				"chalk": "^2.4.0",
+				"is-es2016-keyword": "^1.0.0",
+				"js-tokens": "^3.0.0"
+			},
+			"dependencies": {
+				"js-tokens": {
+					"version": "3.0.2",
+					"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+					"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+					"dev": true
+				}
+			}
+		},
+		"home-or-tmp": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+			"integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+			"dev": true,
+			"requires": {
+				"os-homedir": "^1.0.0",
+				"os-tmpdir": "^1.0.1"
+			}
+		},
+		"http-signature": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+			"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+			"dev": true,
+			"requires": {
+				"assert-plus": "^1.0.0",
+				"jsprim": "^1.2.2",
+				"sshpk": "^1.7.0"
+			}
+		},
+		"https-proxy-agent": {
+			"version": "2.2.1",
+			"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
+			"integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
+			"dev": true,
+			"requires": {
+				"agent-base": "^4.1.0",
+				"debug": "^3.1.0"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "3.2.6",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
+					"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
+					"dev": true,
+					"requires": {
+						"ms": "^2.1.1"
+					}
+				}
+			}
+		},
+		"iconv-lite": {
+			"version": "0.4.11",
+			"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.11.tgz",
+			"integrity": "sha1-LstC/SlHRJIiCaLnxATayHk9it4=",
+			"dev": true
+		},
+		"ieee754": {
+			"version": "1.1.13",
+			"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+			"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+			"dev": true
+		},
+		"ignore": {
+			"version": "4.0.6",
+			"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+			"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+			"dev": true
+		},
+		"import-lazy": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz",
+			"integrity": "sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ==",
+			"dev": true
+		},
+		"indent-string": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-1.2.2.tgz",
+			"integrity": "sha1-25m8xYPrarux5I3LsZmamGBBy2s=",
+			"dev": true,
+			"requires": {
+				"get-stdin": "^4.0.1",
+				"minimist": "^1.1.0",
+				"repeating": "^1.1.0"
+			},
+			"dependencies": {
+				"repeating": {
+					"version": "1.1.3",
+					"resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz",
+					"integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=",
+					"dev": true,
+					"requires": {
+						"is-finite": "^1.0.0"
+					}
+				}
+			}
+		},
+		"inflight": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+			"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+			"dev": true,
+			"requires": {
+				"once": "^1.3.0",
+				"wrappy": "1"
+			}
+		},
+		"inherits": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+			"dev": true
+		},
+		"invariant": {
+			"version": "2.2.4",
+			"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+			"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+			"dev": true,
+			"requires": {
+				"loose-envify": "^1.0.0"
+			}
+		},
+		"ip": {
+			"version": "1.1.5",
+			"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
+			"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
+			"dev": true
+		},
+		"is-accessor-descriptor": {
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+			"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+			"dev": true,
+			"requires": {
+				"kind-of": "^3.0.2"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "3.2.2",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+					"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"is-buffer": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+			"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+			"dev": true
+		},
+		"is-ci": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
+			"integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
+			"dev": true,
+			"requires": {
+				"ci-info": "^1.5.0"
+			}
+		},
+		"is-data-descriptor": {
+			"version": "0.1.4",
+			"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+			"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+			"dev": true,
+			"requires": {
+				"kind-of": "^3.0.2"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "3.2.2",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+					"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"is-descriptor": {
+			"version": "0.1.6",
+			"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+			"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+			"dev": true,
+			"requires": {
+				"is-accessor-descriptor": "^0.1.6",
+				"is-data-descriptor": "^0.1.4",
+				"kind-of": "^5.0.0"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "5.1.0",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+					"integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+					"dev": true
+				}
+			}
+		},
+		"is-docker": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-1.1.0.tgz",
+			"integrity": "sha1-8EN01O7lMQ6ajhE78UlUEeRhdqE=",
+			"dev": true
+		},
+		"is-es2016-keyword": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz",
+			"integrity": "sha1-9uVOEQxeT40mXmnS7Q6vjPX0dxg=",
+			"dev": true
+		},
+		"is-extendable": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+			"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+			"dev": true
+		},
+		"is-extglob": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+			"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+			"dev": true
+		},
+		"is-finite": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+			"integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+			"dev": true,
+			"requires": {
+				"number-is-nan": "^1.0.0"
+			}
+		},
+		"is-fullwidth-code-point": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+			"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+			"dev": true,
+			"requires": {
+				"number-is-nan": "^1.0.0"
+			}
+		},
+		"is-glob": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+			"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+			"dev": true,
+			"requires": {
+				"is-extglob": "^1.0.0"
+			},
+			"dependencies": {
+				"is-extglob": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+					"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+					"dev": true
+				}
+			}
+		},
+		"is-jquery-obj": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/is-jquery-obj/-/is-jquery-obj-0.1.1.tgz",
+			"integrity": "sha512-18toSebUVF7y717dgw/Dzn6djOCqrkiDp3MhB8P6TdKyCVkbD1ZwE7Uz8Hwx6hUPTvKjbyYH9ncXT4ts4qLaSA==",
+			"dev": true
+		},
+		"is-module": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+			"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+			"dev": true
+		},
+		"is-number": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+			"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+			"dev": true,
+			"requires": {
+				"kind-of": "^3.0.2"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "3.2.2",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+					"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"is-path-cwd": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+			"integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+			"dev": true
+		},
+		"is-path-in-cwd": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+			"integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+			"dev": true,
+			"requires": {
+				"is-path-inside": "^1.0.0"
+			}
+		},
+		"is-path-inside": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+			"integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+			"dev": true,
+			"requires": {
+				"path-is-inside": "^1.0.1"
+			}
+		},
+		"is-plain-object": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+			"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+			"dev": true,
+			"requires": {
+				"isobject": "^3.0.1"
+			}
+		},
+		"is-stream": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+			"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+			"dev": true
+		},
+		"is-typedarray": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+			"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+			"dev": true
+		},
+		"is-utf8": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+			"integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+			"dev": true
+		},
+		"is-windows": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+			"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+			"dev": true
+		},
+		"isarray": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+			"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+			"dev": true
+		},
+		"isexe": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+			"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+			"dev": true
+		},
+		"isobject": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+			"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+			"dev": true
+		},
+		"isstream": {
+			"version": "0.1.2",
+			"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+			"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+			"dev": true
+		},
+		"js-levenshtein": {
+			"version": "1.1.6",
+			"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
+			"integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==",
+			"dev": true
+		},
+		"js-tokens": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+			"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+			"dev": true
+		},
+		"jsbn": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+			"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+			"dev": true
+		},
+		"jsesc": {
+			"version": "2.5.2",
+			"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+			"integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+			"dev": true
+		},
+		"json-schema": {
+			"version": "0.2.3",
+			"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+			"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+			"dev": true
+		},
+		"json-schema-traverse": {
+			"version": "0.4.1",
+			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+			"dev": true
+		},
+		"json-stringify-safe": {
+			"version": "5.0.1",
+			"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+			"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+			"dev": true
+		},
+		"json5": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz",
+			"integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==",
+			"dev": true,
+			"requires": {
+				"minimist": "^1.2.0"
+			}
+		},
+		"jsprim": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+			"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+			"dev": true,
+			"requires": {
+				"assert-plus": "1.0.0",
+				"extsprintf": "1.3.0",
+				"json-schema": "0.2.3",
+				"verror": "1.10.0"
+			}
+		},
+		"kind-of": {
+			"version": "6.0.2",
+			"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+			"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+			"dev": true
+		},
+		"lazystream": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+			"integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+			"dev": true,
+			"requires": {
+				"readable-stream": "^2.0.5"
+			}
+		},
+		"linux-platform-info": {
+			"version": "0.0.3",
+			"resolved": "https://registry.npmjs.org/linux-platform-info/-/linux-platform-info-0.0.3.tgz",
+			"integrity": "sha1-La4yQ4Xmbj11W+yD+Gx77qYc64M=",
+			"dev": true,
+			"requires": {
+				"os-family": "^1.0.0"
+			}
+		},
+		"lodash": {
+			"version": "4.17.11",
+			"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+			"integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+			"dev": true
+		},
+		"log-update-async-hook": {
+			"version": "2.0.2",
+			"resolved": "https://registry.npmjs.org/log-update-async-hook/-/log-update-async-hook-2.0.2.tgz",
+			"integrity": "sha512-HQwkKFTZeUOrDi1Duf2CSUa/pSpcaCHKLdx3D/Z16DsipzByOBffcg5y0JZA1q0n80dYgLXe2hFM9JGNgBsTDw==",
+			"dev": true,
+			"requires": {
+				"ansi-escapes": "^2.0.0",
+				"async-exit-hook": "^1.1.2",
+				"onetime": "^2.0.1",
+				"wrap-ansi": "^2.1.0"
+			}
+		},
+		"loose-envify": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+			"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+			"dev": true,
+			"requires": {
+				"js-tokens": "^3.0.0 || ^4.0.0"
+			}
+		},
+		"lru-cache": {
+			"version": "2.6.3",
+			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.3.tgz",
+			"integrity": "sha1-UczQtPwMhDWH16VwnOTTt2Kb7cU=",
+			"dev": true
+		},
+		"make-dir": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
+			"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
+			"dev": true,
+			"requires": {
+				"pify": "^3.0.0"
+			},
+			"dependencies": {
+				"pify": {
+					"version": "3.0.0",
+					"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+					"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+					"dev": true
+				}
+			}
+		},
+		"map-cache": {
+			"version": "0.2.2",
+			"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+			"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+			"dev": true
+		},
+		"map-reverse": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/map-reverse/-/map-reverse-1.0.1.tgz",
+			"integrity": "sha1-J06fUAphEVMYO1uNhJCpwcI+4xA=",
+			"dev": true
+		},
+		"map-visit": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+			"integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+			"dev": true,
+			"requires": {
+				"object-visit": "^1.0.0"
+			}
+		},
+		"match-url-wildcard": {
+			"version": "0.0.4",
+			"resolved": "https://registry.npmjs.org/match-url-wildcard/-/match-url-wildcard-0.0.4.tgz",
+			"integrity": "sha512-R1XhQaamUZPWLOPtp4ig5j+3jctN+skhgRmEQTUamMzmNtRG69QEirQs0NZKLtHMR7tzWpmtnS4Eqv65DcgXUA==",
+			"dev": true,
+			"requires": {
+				"escape-string-regexp": "^1.0.5"
+			}
+		},
+		"merge-stream": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz",
+			"integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=",
+			"dev": true,
+			"requires": {
+				"readable-stream": "^2.0.1"
+			}
+		},
+		"merge2": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz",
+			"integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==",
+			"dev": true
+		},
+		"micromatch": {
+			"version": "3.1.10",
+			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+			"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+			"dev": true,
+			"requires": {
+				"arr-diff": "^4.0.0",
+				"array-unique": "^0.3.2",
+				"braces": "^2.3.1",
+				"define-property": "^2.0.2",
+				"extend-shallow": "^3.0.2",
+				"extglob": "^2.0.4",
+				"fragment-cache": "^0.2.1",
+				"kind-of": "^6.0.2",
+				"nanomatch": "^1.2.9",
+				"object.pick": "^1.3.0",
+				"regex-not": "^1.0.0",
+				"snapdragon": "^0.8.1",
+				"to-regex": "^3.0.2"
+			}
+		},
+		"mime": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+			"integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==",
+			"dev": true
+		},
+		"mime-db": {
+			"version": "1.40.0",
+			"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+			"integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==",
+			"dev": true
+		},
+		"mime-types": {
+			"version": "2.1.24",
+			"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+			"integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+			"dev": true,
+			"requires": {
+				"mime-db": "1.40.0"
+			}
+		},
+		"mimic-fn": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
+			"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
+			"dev": true
+		},
+		"minimatch": {
+			"version": "3.0.4",
+			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+			"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+			"dev": true,
+			"requires": {
+				"brace-expansion": "^1.1.7"
+			}
+		},
+		"minimist": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+			"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+			"dev": true
+		},
+		"mixin-deep": {
+			"version": "1.3.2",
+			"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+			"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+			"dev": true,
+			"requires": {
+				"for-in": "^1.0.2",
+				"is-extendable": "^1.0.1"
+			},
+			"dependencies": {
+				"is-extendable": {
+					"version": "1.0.1",
+					"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+					"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+					"dev": true,
+					"requires": {
+						"is-plain-object": "^2.0.4"
+					}
+				}
+			}
+		},
+		"mkdirp": {
+			"version": "0.5.1",
+			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+			"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+			"dev": true,
+			"requires": {
+				"minimist": "0.0.8"
+			},
+			"dependencies": {
+				"minimist": {
+					"version": "0.0.8",
+					"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+					"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+					"dev": true
+				}
+			}
+		},
+		"moment": {
+			"version": "2.24.0",
+			"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
+			"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
+			"dev": true
+		},
+		"moment-duration-format-commonjs": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/moment-duration-format-commonjs/-/moment-duration-format-commonjs-1.0.0.tgz",
+			"integrity": "sha512-MVFR4hIh4jfuwSCPBEE5CCwn3refvTsxK/Yv/DpKJ6YcNnCimlVJ6DQeTJG1KVQPw1o8m3tkbHE9gVjivyv9iA==",
+			"dev": true
+		},
+		"ms": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+			"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+			"dev": true
+		},
+		"mustache": {
+			"version": "2.3.2",
+			"resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz",
+			"integrity": "sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ==",
+			"dev": true
+		},
+		"nanoid": {
+			"version": "1.3.4",
+			"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.3.4.tgz",
+			"integrity": "sha512-4ug4BsuHxiVHoRUe1ud6rUFT3WUMmjXt1W0quL0CviZQANdan7D8kqN5/maw53hmAApY/jfzMRkC57BNNs60ZQ==",
+			"dev": true
+		},
+		"nanomatch": {
+			"version": "1.2.13",
+			"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+			"integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+			"dev": true,
+			"requires": {
+				"arr-diff": "^4.0.0",
+				"array-unique": "^0.3.2",
+				"define-property": "^2.0.2",
+				"extend-shallow": "^3.0.2",
+				"fragment-cache": "^0.2.1",
+				"is-windows": "^1.0.2",
+				"kind-of": "^6.0.2",
+				"object.pick": "^1.3.0",
+				"regex-not": "^1.0.0",
+				"snapdragon": "^0.8.1",
+				"to-regex": "^3.0.1"
+			}
+		},
+		"node-releases": {
+			"version": "1.1.21",
+			"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.21.tgz",
+			"integrity": "sha512-TwnURTCjc8a+ElJUjmDqU6+12jhli1Q61xOQmdZ7ECZVBZuQpN/1UnembiIHDM1wCcfLvh5wrWXUF5H6ufX64Q==",
+			"dev": true,
+			"requires": {
+				"semver": "^5.3.0"
+			}
+		},
+		"node-version": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/node-version/-/node-version-1.2.0.tgz",
+			"integrity": "sha512-ma6oU4Sk0qOoKEAymVoTvk8EdXEobdS7m/mAGhDJ8Rouugho48crHBORAmy5BoOcv8wraPM6xumapQp5hl4iIQ==",
+			"dev": true
+		},
+		"normalize-path": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+			"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+			"dev": true,
+			"requires": {
+				"remove-trailing-separator": "^1.0.1"
+			}
+		},
+		"number-is-nan": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+			"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+			"dev": true
+		},
+		"oauth-sign": {
+			"version": "0.9.0",
+			"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+			"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+			"dev": true
+		},
+		"object-assign": {
+			"version": "4.1.1",
+			"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+			"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+			"dev": true
+		},
+		"object-copy": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+			"integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+			"dev": true,
+			"requires": {
+				"copy-descriptor": "^0.1.0",
+				"define-property": "^0.2.5",
+				"kind-of": "^3.0.3"
+			},
+			"dependencies": {
+				"define-property": {
+					"version": "0.2.5",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+					"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^0.1.0"
+					}
+				},
+				"kind-of": {
+					"version": "3.2.2",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+					"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"object-visit": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+			"integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+			"dev": true,
+			"requires": {
+				"isobject": "^3.0.0"
+			}
+		},
+		"object.pick": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+			"integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+			"dev": true,
+			"requires": {
+				"isobject": "^3.0.1"
+			}
+		},
+		"once": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+			"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+			"dev": true,
+			"requires": {
+				"wrappy": "1"
+			}
+		},
+		"onetime": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+			"integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+			"dev": true,
+			"requires": {
+				"mimic-fn": "^1.0.0"
+			}
+		},
+		"os-family": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/os-family/-/os-family-1.1.0.tgz",
+			"integrity": "sha512-E3Orl5pvDJXnVmpaAA2TeNNpNhTMl4o5HghuWhOivBjEiTnJSrMYSa5uZMek1lBEvu8kKEsa2YgVcGFVDqX/9w==",
+			"dev": true
+		},
+		"os-homedir": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+			"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+			"dev": true
+		},
+		"os-tmpdir": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+			"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+			"dev": true
+		},
+		"p-map": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz",
+			"integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==",
+			"dev": true
+		},
+		"parse5": {
+			"version": "1.5.1",
+			"resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
+			"integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=",
+			"dev": true
+		},
+		"pascalcase": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+			"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+			"dev": true
+		},
+		"path-dirname": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+			"integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+			"dev": true
+		},
+		"path-is-absolute": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+			"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+			"dev": true
+		},
+		"path-is-inside": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+			"integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
+			"dev": true
+		},
+		"path-parse": {
+			"version": "1.0.6",
+			"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+			"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+			"dev": true
+		},
+		"path-type": {
+			"version": "3.0.0",
+			"resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
+			"integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
+			"dev": true,
+			"requires": {
+				"pify": "^3.0.0"
+			},
+			"dependencies": {
+				"pify": {
+					"version": "3.0.0",
+					"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
+					"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
+					"dev": true
+				}
+			}
+		},
+		"pathval": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
+			"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=",
+			"dev": true
+		},
+		"performance-now": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+			"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+			"dev": true
+		},
+		"pify": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+			"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+			"dev": true
+		},
+		"pinkie": {
+			"version": "2.0.4",
+			"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+			"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+			"dev": true
+		},
+		"pinkie-promise": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+			"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+			"dev": true,
+			"requires": {
+				"pinkie": "^2.0.0"
+			}
+		},
+		"pngjs": {
+			"version": "3.4.0",
+			"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
+			"integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==",
+			"dev": true
+		},
+		"posix-character-classes": {
+			"version": "0.1.1",
+			"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+			"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+			"dev": true
+		},
+		"private": {
+			"version": "0.1.8",
+			"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+			"integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+			"dev": true
+		},
+		"process-nextick-args": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+			"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+			"dev": true
+		},
+		"promisify-event": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/promisify-event/-/promisify-event-1.0.0.tgz",
+			"integrity": "sha1-vXUj6ga3AWLzcJeQFrU6aGxg6Q8=",
+			"dev": true,
+			"requires": {
+				"pinkie-promise": "^2.0.0"
+			}
+		},
+		"pseudomap": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+			"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
+			"dev": true
+		},
+		"psl": {
+			"version": "1.1.33",
+			"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.33.tgz",
+			"integrity": "sha512-LTDP2uSrsc7XCb5lO7A8BI1qYxRe/8EqlRvMeEl6rsnYAqDOl8xHR+8lSAIVfrNaSAlTPTNOCgNjWcoUL3AZsw==",
+			"dev": true
+		},
+		"punycode": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+			"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+			"dev": true
+		},
+		"q": {
+			"version": "1.4.1",
+			"resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
+			"integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=",
+			"dev": true
+		},
+		"qrcode-terminal": {
+			"version": "0.10.0",
+			"resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.10.0.tgz",
+			"integrity": "sha1-p2pI4mEKGPl/o6K9UytoKs/4bFM=",
+			"dev": true
+		},
+		"qs": {
+			"version": "6.5.2",
+			"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+			"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+			"dev": true
+		},
+		"read-file-relative": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz",
+			"integrity": "sha1-mPfZbqoh0rTHov69Y9L8jPNen5s=",
+			"dev": true,
+			"requires": {
+				"callsite": "^1.0.0"
+			}
+		},
+		"readable-stream": {
+			"version": "2.3.6",
+			"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+			"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+			"dev": true,
+			"requires": {
+				"core-util-is": "~1.0.0",
+				"inherits": "~2.0.3",
+				"isarray": "~1.0.0",
+				"process-nextick-args": "~2.0.0",
+				"safe-buffer": "~5.1.1",
+				"string_decoder": "~1.1.1",
+				"util-deprecate": "~1.0.1"
+			}
+		},
+		"regenerate": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
+			"integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
+			"dev": true
+		},
+		"regenerate-unicode-properties": {
+			"version": "8.1.0",
+			"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz",
+			"integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==",
+			"dev": true,
+			"requires": {
+				"regenerate": "^1.4.0"
+			}
+		},
+		"regenerator-runtime": {
+			"version": "0.11.1",
+			"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+			"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+			"dev": true
+		},
+		"regenerator-transform": {
+			"version": "0.14.0",
+			"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.0.tgz",
+			"integrity": "sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==",
+			"dev": true,
+			"requires": {
+				"private": "^0.1.6"
+			}
+		},
+		"regex-not": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+			"integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+			"dev": true,
+			"requires": {
+				"extend-shallow": "^3.0.2",
+				"safe-regex": "^1.1.0"
+			}
+		},
+		"regexp-tree": {
+			"version": "0.1.10",
+			"resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.10.tgz",
+			"integrity": "sha512-K1qVSbcedffwuIslMwpe6vGlj+ZXRnGkvjAtFHfDZZZuEdA/h0dxljAPu9vhUo6Rrx2U2AwJ+nSQ6hK+lrP5MQ==",
+			"dev": true
+		},
+		"regexpu-core": {
+			"version": "4.5.4",
+			"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz",
+			"integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==",
+			"dev": true,
+			"requires": {
+				"regenerate": "^1.4.0",
+				"regenerate-unicode-properties": "^8.0.2",
+				"regjsgen": "^0.5.0",
+				"regjsparser": "^0.6.0",
+				"unicode-match-property-ecmascript": "^1.0.4",
+				"unicode-match-property-value-ecmascript": "^1.1.0"
+			}
+		},
+		"regjsgen": {
+			"version": "0.5.0",
+			"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz",
+			"integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==",
+			"dev": true
+		},
+		"regjsparser": {
+			"version": "0.6.0",
+			"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz",
+			"integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==",
+			"dev": true,
+			"requires": {
+				"jsesc": "~0.5.0"
+			},
+			"dependencies": {
+				"jsesc": {
+					"version": "0.5.0",
+					"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+					"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+					"dev": true
+				}
+			}
+		},
+		"remove-trailing-separator": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+			"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+			"dev": true
+		},
+		"repeat-element": {
+			"version": "1.1.3",
+			"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+			"integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+			"dev": true
+		},
+		"repeat-string": {
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+			"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+			"dev": true
+		},
+		"repeating": {
+			"version": "2.0.1",
+			"resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+			"integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+			"dev": true,
+			"requires": {
+				"is-finite": "^1.0.0"
+			}
+		},
+		"replicator": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/replicator/-/replicator-1.0.3.tgz",
+			"integrity": "sha512-WsKsraaM0x0QHy5CtzdgFXUxyowoBhyNkmPqmZShW6h+rOWnyT6Od3zRdTX9r616rAA6kDC9MKQGnSM/CJKfVQ==",
+			"dev": true
+		},
+		"request": {
+			"version": "2.88.0",
+			"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
+			"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
+			"dev": true,
+			"requires": {
+				"aws-sign2": "~0.7.0",
+				"aws4": "^1.8.0",
+				"caseless": "~0.12.0",
+				"combined-stream": "~1.0.6",
+				"extend": "~3.0.2",
+				"forever-agent": "~0.6.1",
+				"form-data": "~2.3.2",
+				"har-validator": "~5.1.0",
+				"http-signature": "~1.2.0",
+				"is-typedarray": "~1.0.0",
+				"isstream": "~0.1.2",
+				"json-stringify-safe": "~5.0.1",
+				"mime-types": "~2.1.19",
+				"oauth-sign": "~0.9.0",
+				"performance-now": "^2.1.0",
+				"qs": "~6.5.2",
+				"safe-buffer": "^5.1.2",
+				"tough-cookie": "~2.4.3",
+				"tunnel-agent": "^0.6.0",
+				"uuid": "^3.3.2"
+			},
+			"dependencies": {
+				"tough-cookie": {
+					"version": "2.4.3",
+					"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
+					"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
+					"dev": true,
+					"requires": {
+						"psl": "^1.1.24",
+						"punycode": "^1.4.1"
+					}
+				}
+			}
+		},
+		"resolve": {
+			"version": "1.11.0",
+			"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
+			"integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
+			"dev": true,
+			"requires": {
+				"path-parse": "^1.0.6"
+			}
+		},
+		"resolve-cwd": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-1.0.0.tgz",
+			"integrity": "sha1-Tq7qQe0EDRcCRX32SkKysH0kb58=",
+			"dev": true,
+			"requires": {
+				"resolve-from": "^2.0.0"
+			},
+			"dependencies": {
+				"resolve-from": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
+					"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=",
+					"dev": true
+				}
+			}
+		},
+		"resolve-from": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+			"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+			"dev": true
+		},
+		"resolve-url": {
+			"version": "0.2.1",
+			"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+			"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+			"dev": true
+		},
+		"ret": {
+			"version": "0.1.15",
+			"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+			"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+			"dev": true
+		},
+		"rimraf": {
+			"version": "2.6.3",
+			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+			"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+			"dev": true,
+			"requires": {
+				"glob": "^7.1.3"
+			}
+		},
+		"rollup": {
+			"version": "1.12.3",
+			"resolved": "https://registry.npmjs.org/rollup/-/rollup-1.12.3.tgz",
+			"integrity": "sha512-ueWhPijWN+GaPgD3l77hXih/gcDXmYph6sWeQegwBYtaqAE834e8u+MC2wT6FKIUsz1DBOyOXAQXUZB+rjWDoQ==",
+			"dev": true,
+			"requires": {
+				"@types/estree": "0.0.39",
+				"@types/node": "^12.0.2",
+				"acorn": "^6.1.1"
+			}
+		},
+		"rollup-plugin-babel": {
+			"version": "4.3.2",
+			"resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.3.2.tgz",
+			"integrity": "sha512-KfnizE258L/4enADKX61ozfwGHoqYauvoofghFJBhFnpH9Sb9dNPpWg8QHOaAfVASUYV8w0mCx430i9z0LJoJg==",
+			"dev": true,
+			"requires": {
+				"@babel/helper-module-imports": "^7.0.0",
+				"rollup-pluginutils": "^2.3.0"
+			}
+		},
+		"rollup-plugin-json": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz",
+			"integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==",
+			"dev": true,
+			"requires": {
+				"rollup-pluginutils": "^2.5.0"
+			}
+		},
+		"rollup-plugin-node-resolve": {
+			"version": "5.0.0",
+			"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.0.0.tgz",
+			"integrity": "sha512-JUFr7DkFps3div9DYwpSg0O+s8zuSSRASUZUVNx6h6zhw2m8vcpToeS68JDPsFbmisMVSMYK0IxftngCRv7M9Q==",
+			"dev": true,
+			"requires": {
+				"@types/resolve": "0.0.8",
+				"builtin-modules": "^3.1.0",
+				"is-module": "^1.0.0",
+				"resolve": "^1.10.1",
+				"rollup-pluginutils": "^2.7.0"
+			}
+		},
+		"rollup-pluginutils": {
+			"version": "2.7.1",
+			"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.7.1.tgz",
+			"integrity": "sha512-3nRf3buQGR9qz/IsSzhZAJyoK663kzseps8itkYHr+Z7ESuaffEPfgRinxbCRA0pf0gzLqkNKkSb8aNVTq75NA==",
+			"dev": true,
+			"requires": {
+				"estree-walker": "^0.6.0",
+				"micromatch": "^3.1.10"
+			}
+		},
+		"safe-buffer": {
+			"version": "5.1.2",
+			"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+			"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+			"dev": true
+		},
+		"safe-regex": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+			"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+			"dev": true,
+			"requires": {
+				"ret": "~0.1.10"
+			}
+		},
+		"safer-buffer": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+			"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+			"dev": true
+		},
+		"sanitize-filename": {
+			"version": "1.6.1",
+			"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.1.tgz",
+			"integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=",
+			"dev": true,
+			"requires": {
+				"truncate-utf8-bytes": "^1.0.0"
+			}
+		},
+		"sauce-connect-launcher": {
+			"version": "1.2.7",
+			"resolved": "https://registry.npmjs.org/sauce-connect-launcher/-/sauce-connect-launcher-1.2.7.tgz",
+			"integrity": "sha512-v07+QhFrxgz3seMFuRSonu3gW1s6DbcLQlFhjsRrmKUauzPbbudHdnn91WYgEwhoZVdPNzeZpAEJwcQyd9xnTA==",
+			"dev": true,
+			"requires": {
+				"adm-zip": "~0.4.3",
+				"async": "^2.1.2",
+				"https-proxy-agent": "^2.2.1",
+				"lodash": "^4.16.6",
+				"rimraf": "^2.5.4"
+			},
+			"dependencies": {
+				"async": {
+					"version": "2.6.2",
+					"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
+					"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
+					"dev": true,
+					"requires": {
+						"lodash": "^4.17.11"
+					}
+				}
+			}
+		},
+		"saucelabs-connector": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/saucelabs-connector/-/saucelabs-connector-0.3.0.tgz",
+			"integrity": "sha512-r0PWFUZeWMoWaKWhvnaHpro5VfpLbg+avKdjb0bs+xSTNh4S6sgjVJMhM8vSjOXog2DjZVe1Agv4Ta5GCMLMog==",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^5.8.20",
+				"lodash": "^4.13.1",
+				"os-family": "^1.0.0",
+				"pify": "^2.3.0",
+				"pinkie": "^2.0.4",
+				"read-file-relative": "^1.2.0",
+				"request": "^2.67.0",
+				"sauce-connect-launcher": "^1.2.5",
+				"wd": "^1.2.0"
+			},
+			"dependencies": {
+				"babel-runtime": {
+					"version": "5.8.38",
+					"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
+					"integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=",
+					"dev": true,
+					"requires": {
+						"core-js": "^1.0.0"
+					}
+				},
+				"core-js": {
+					"version": "1.2.7",
+					"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+					"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
+					"dev": true
+				}
+			}
+		},
+		"semver": {
+			"version": "5.7.0",
+			"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+			"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+			"dev": true
+		},
+		"set-value": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
+			"integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+			"dev": true,
+			"requires": {
+				"extend-shallow": "^2.0.1",
+				"is-extendable": "^0.1.1",
+				"is-plain-object": "^2.0.3",
+				"split-string": "^3.0.1"
+			},
+			"dependencies": {
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				}
+			}
+		},
+		"slash": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+			"integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+			"dev": true
+		},
+		"snapdragon": {
+			"version": "0.8.2",
+			"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+			"integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+			"dev": true,
+			"requires": {
+				"base": "^0.11.1",
+				"debug": "^2.2.0",
+				"define-property": "^0.2.5",
+				"extend-shallow": "^2.0.1",
+				"map-cache": "^0.2.2",
+				"source-map": "^0.5.6",
+				"source-map-resolve": "^0.5.0",
+				"use": "^3.1.0"
+			},
+			"dependencies": {
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
+				"define-property": {
+					"version": "0.2.5",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+					"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^0.1.0"
+					}
+				},
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				},
+				"ms": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+					"dev": true
+				}
+			}
+		},
+		"snapdragon-node": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+			"integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+			"dev": true,
+			"requires": {
+				"define-property": "^1.0.0",
+				"isobject": "^3.0.0",
+				"snapdragon-util": "^3.0.1"
+			},
+			"dependencies": {
+				"define-property": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+					"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^1.0.0"
+					}
+				},
+				"is-accessor-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+					"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-data-descriptor": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+					"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+					"dev": true,
+					"requires": {
+						"kind-of": "^6.0.0"
+					}
+				},
+				"is-descriptor": {
+					"version": "1.0.2",
+					"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+					"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+					"dev": true,
+					"requires": {
+						"is-accessor-descriptor": "^1.0.0",
+						"is-data-descriptor": "^1.0.0",
+						"kind-of": "^6.0.2"
+					}
+				}
+			}
+		},
+		"snapdragon-util": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+			"integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+			"dev": true,
+			"requires": {
+				"kind-of": "^3.2.0"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "3.2.2",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+					"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"source-map": {
+			"version": "0.5.7",
+			"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+			"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+			"dev": true
+		},
+		"source-map-resolve": {
+			"version": "0.5.2",
+			"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
+			"integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+			"dev": true,
+			"requires": {
+				"atob": "^2.1.1",
+				"decode-uri-component": "^0.2.0",
+				"resolve-url": "^0.2.1",
+				"source-map-url": "^0.4.0",
+				"urix": "^0.1.0"
+			}
+		},
+		"source-map-support": {
+			"version": "0.5.12",
+			"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz",
+			"integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
+			"dev": true,
+			"requires": {
+				"buffer-from": "^1.0.0",
+				"source-map": "^0.6.0"
+			},
+			"dependencies": {
+				"source-map": {
+					"version": "0.6.1",
+					"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+					"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+					"dev": true
+				}
+			}
+		},
+		"source-map-url": {
+			"version": "0.4.0",
+			"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+			"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+			"dev": true
+		},
+		"split-string": {
+			"version": "3.1.0",
+			"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+			"integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+			"dev": true,
+			"requires": {
+				"extend-shallow": "^3.0.0"
+			}
+		},
+		"sshpk": {
+			"version": "1.16.1",
+			"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+			"integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+			"dev": true,
+			"requires": {
+				"asn1": "~0.2.3",
+				"assert-plus": "^1.0.0",
+				"bcrypt-pbkdf": "^1.0.0",
+				"dashdash": "^1.12.0",
+				"ecc-jsbn": "~0.1.1",
+				"getpass": "^0.1.1",
+				"jsbn": "~0.1.0",
+				"safer-buffer": "^2.0.2",
+				"tweetnacl": "~0.14.0"
+			}
+		},
+		"stackframe": {
+			"version": "0.3.1",
+			"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-0.3.1.tgz",
+			"integrity": "sha1-M6qE8Rd6VUjIk1Uzy/6zQgl19aQ=",
+			"dev": true
+		},
+		"static-extend": {
+			"version": "0.1.2",
+			"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+			"integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+			"dev": true,
+			"requires": {
+				"define-property": "^0.2.5",
+				"object-copy": "^0.1.0"
+			},
+			"dependencies": {
+				"define-property": {
+					"version": "0.2.5",
+					"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+					"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+					"dev": true,
+					"requires": {
+						"is-descriptor": "^0.1.0"
+					}
+				}
+			}
+		},
+		"string-width": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+			"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+			"dev": true,
+			"requires": {
+				"code-point-at": "^1.0.0",
+				"is-fullwidth-code-point": "^1.0.0",
+				"strip-ansi": "^3.0.0"
+			}
+		},
+		"string_decoder": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+			"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+			"dev": true,
+			"requires": {
+				"safe-buffer": "~5.1.0"
+			}
+		},
+		"strip-ansi": {
+			"version": "3.0.1",
+			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+			"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+			"dev": true,
+			"requires": {
+				"ansi-regex": "^2.0.0"
+			}
+		},
+		"strip-bom": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
+			"integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
+			"dev": true,
+			"requires": {
+				"is-utf8": "^0.2.0"
+			}
+		},
+		"supports-color": {
+			"version": "5.5.0",
+			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+			"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+			"dev": true,
+			"requires": {
+				"has-flag": "^3.0.0"
+			}
+		},
+		"tar-stream": {
+			"version": "1.6.2",
+			"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz",
+			"integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==",
+			"dev": true,
+			"requires": {
+				"bl": "^1.0.0",
+				"buffer-alloc": "^1.2.0",
+				"end-of-stream": "^1.0.0",
+				"fs-constants": "^1.0.0",
+				"readable-stream": "^2.3.0",
+				"to-buffer": "^1.1.1",
+				"xtend": "^4.0.0"
+			}
+		},
+		"testcafe": {
+			"version": "1.3.1",
+			"resolved": "https://registry.npmjs.org/testcafe/-/testcafe-1.3.1.tgz",
+			"integrity": "sha512-5IkyFxKBdrUut9JEmGR8lU4qbxL9N9F/3yNJqfLF29bpRfrmJY2FZdAYQ1iHEayfCcSTxQxcqRCEkVsmRTaI4g==",
+			"dev": true,
+			"requires": {
+				"@types/node": "^10.12.19",
+				"async-exit-hook": "^1.1.2",
+				"babel-core": "^6.22.1",
+				"babel-plugin-transform-class-properties": "^6.24.1",
+				"babel-plugin-transform-for-of-as-array": "^1.1.1",
+				"babel-plugin-transform-runtime": "^6.22.0",
+				"babel-preset-env": "^1.1.8",
+				"babel-preset-flow": "^6.23.0",
+				"babel-preset-stage-2": "^6.22.0",
+				"babel-runtime": "^6.22.0",
+				"bin-v8-flags-filter": "^1.1.2",
+				"callsite": "^1.0.0",
+				"callsite-record": "^4.0.0",
+				"chai": "^4.1.2",
+				"chalk": "^1.1.0",
+				"chrome-emulated-devices-list": "^0.1.0",
+				"chrome-remote-interface": "^0.25.3",
+				"coffeescript": "^2.3.1",
+				"commander": "^2.8.1",
+				"debug": "^2.2.0",
+				"dedent": "^0.4.0",
+				"del": "^3.0.0",
+				"elegant-spinner": "^1.0.1",
+				"emittery": "^0.4.1",
+				"endpoint-utils": "^1.0.2",
+				"error-stack-parser": "^1.3.6",
+				"globby": "^9.2.0",
+				"graceful-fs": "^4.1.11",
+				"graphlib": "^2.1.5",
+				"import-lazy": "^3.1.0",
+				"indent-string": "^1.2.2",
+				"is-ci": "^1.0.10",
+				"is-docker": "^1.1.0",
+				"is-glob": "^2.0.1",
+				"is-stream": "^1.1.0",
+				"json5": "^2.1.0",
+				"lodash": "^4.17.11",
+				"log-update-async-hook": "^2.0.2",
+				"make-dir": "^1.3.0",
+				"map-reverse": "^1.0.1",
+				"moment": "^2.10.3",
+				"moment-duration-format-commonjs": "^1.0.0",
+				"mustache": "^2.1.2",
+				"nanoid": "^1.0.1",
+				"node-version": "^1.0.0",
+				"os-family": "^1.0.0",
+				"parse5": "^1.5.0",
+				"pify": "^2.3.0",
+				"pinkie": "^2.0.4",
+				"pngjs": "^3.3.1",
+				"promisify-event": "^1.0.0",
+				"qrcode-terminal": "^0.10.0",
+				"read-file-relative": "^1.2.0",
+				"replicator": "^1.0.3",
+				"resolve-cwd": "^1.0.0",
+				"resolve-from": "^4.0.0",
+				"sanitize-filename": "^1.6.0",
+				"source-map-support": "^0.5.5",
+				"strip-bom": "^2.0.0",
+				"testcafe-browser-tools": "1.6.8",
+				"testcafe-hammerhead": "14.6.10",
+				"testcafe-legacy-api": "3.1.11",
+				"testcafe-reporter-json": "^2.1.0",
+				"testcafe-reporter-list": "^2.1.0",
+				"testcafe-reporter-minimal": "^2.1.0",
+				"testcafe-reporter-spec": "^2.1.1",
+				"testcafe-reporter-xunit": "^2.1.0",
+				"time-limit-promise": "^1.0.2",
+				"tmp": "0.0.28",
+				"tree-kill": "^1.1.0",
+				"typescript": "^3.3.3",
+				"useragent": "^2.1.7"
+			},
+			"dependencies": {
+				"@types/node": {
+					"version": "10.14.12",
+					"resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.12.tgz",
+					"integrity": "sha512-QcAKpaO6nhHLlxWBvpc4WeLrTvPqlHOvaj0s5GriKkA1zq+bsFBPpfYCvQhLqLgYlIko8A9YrPdaMHCo5mBcpg==",
+					"dev": true
+				},
+				"ansi-styles": {
+					"version": "2.2.1",
+					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+					"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+					"dev": true
+				},
+				"chalk": {
+					"version": "1.1.3",
+					"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+					"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+					"dev": true,
+					"requires": {
+						"ansi-styles": "^2.2.1",
+						"escape-string-regexp": "^1.0.2",
+						"has-ansi": "^2.0.0",
+						"strip-ansi": "^3.0.0",
+						"supports-color": "^2.0.0"
+					}
+				},
+				"debug": {
+					"version": "2.6.9",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+					"dev": true,
+					"requires": {
+						"ms": "2.0.0"
+					}
+				},
+				"ms": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+					"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+					"dev": true
+				},
+				"supports-color": {
+					"version": "2.0.0",
+					"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+					"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+					"dev": true
+				}
+			}
+		},
+		"testcafe-browser-provider-saucelabs": {
+			"version": "1.7.0",
+			"resolved": "https://registry.npmjs.org/testcafe-browser-provider-saucelabs/-/testcafe-browser-provider-saucelabs-1.7.0.tgz",
+			"integrity": "sha512-M7sRL2MgWuFmnIUJi/sB7w39WP4zSHUl2pDLhTy0mSUwBahM65Berj5t+K5UkAbQFilfLgP4hnkt75c/9RaJ1g==",
+			"dev": true,
+			"requires": {
+				"babel-runtime": "^6.11.6",
+				"desired-capabilities": "^0.1.0",
+				"lodash": "^4.14.2",
+				"pify": "^2.3.0",
+				"pinkie": "^2.0.4",
+				"request": "^2.74.0",
+				"saucelabs-connector": "^0.3.0"
+			}
+		},
+		"testcafe-browser-tools": {
+			"version": "1.6.8",
+			"resolved": "https://registry.npmjs.org/testcafe-browser-tools/-/testcafe-browser-tools-1.6.8.tgz",
+			"integrity": "sha512-xFgwmcAOutSJR6goqO8uUFGF5IF2xRC/Ssh4pB5QZ+bTjYsN5amnjgM+813bDBLelC+HmXKqylviz7Dzxbtbcw==",
+			"dev": true,
+			"requires": {
+				"array-find": "^1.0.0",
+				"babel-runtime": "^5.6.15",
+				"graceful-fs": "^4.1.11",
+				"linux-platform-info": "^0.0.3",
+				"mkdirp": "^0.5.1",
+				"mustache": "^2.1.2",
+				"os-family": "^1.0.0",
+				"pify": "^2.3.0",
+				"pinkie": "^2.0.1",
+				"read-file-relative": "^1.2.0",
+				"which-promise": "^1.0.0"
+			},
+			"dependencies": {
+				"babel-runtime": {
+					"version": "5.8.38",
+					"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
+					"integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=",
+					"dev": true,
+					"requires": {
+						"core-js": "^1.0.0"
+					}
+				},
+				"core-js": {
+					"version": "1.2.7",
+					"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+					"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
+					"dev": true
+				}
+			}
+		},
+		"testcafe-hammerhead": {
+			"version": "14.6.10",
+			"resolved": "https://registry.npmjs.org/testcafe-hammerhead/-/testcafe-hammerhead-14.6.10.tgz",
+			"integrity": "sha512-fG/YTz7wKs6Fd0Fl9WlzO4j/ovDSAGxDLvLAz4ydzIKAdnZMZ22QbjYpfahCVpe9nzq/UHCQpSFdThQTmlFEmA==",
+			"dev": true,
+			"requires": {
+				"acorn-hammerhead": "^0.2.0",
+				"bowser": "1.6.0",
+				"brotli": "^1.3.1",
+				"crypto-md5": "^1.0.0",
+				"css": "2.2.3",
+				"esotope-hammerhead": "^0.2.1",
+				"iconv-lite": "0.4.11",
+				"lodash": "4.17.11",
+				"lru-cache": "2.6.3",
+				"match-url-wildcard": "0.0.4",
+				"merge-stream": "^1.0.1",
+				"mime": "~1.4.1",
+				"mustache": "^2.1.1",
+				"nanoid": "^0.2.2",
+				"os-family": "^1.0.0",
+				"parse5": "2.2.3",
+				"pify": "^2.3.0",
+				"pinkie": "1.0.0",
+				"read-file-relative": "^1.2.0",
+				"semver": "5.5.0",
+				"tough-cookie": "2.3.3",
+				"tunnel-agent": "0.6.0",
+				"webauth": "^1.1.0"
+			},
+			"dependencies": {
+				"nanoid": {
+					"version": "0.2.2",
+					"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-0.2.2.tgz",
+					"integrity": "sha512-GHoRrvNEKiwdkwQ/enKL8AhQkkrBC/2KxMZkDvQzp8OtkpX8ZAmoYJWFVl7l8F2+HcEJUfdg21Ab2wXXfrvACQ==",
+					"dev": true
+				},
+				"parse5": {
+					"version": "2.2.3",
+					"resolved": "https://registry.npmjs.org/parse5/-/parse5-2.2.3.tgz",
+					"integrity": "sha1-DE/EHBAAxea5PUiwP4CDg3g06fY=",
+					"dev": true
+				},
+				"pinkie": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz",
+					"integrity": "sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=",
+					"dev": true
+				},
+				"semver": {
+					"version": "5.5.0",
+					"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
+					"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
+					"dev": true
+				}
+			}
+		},
+		"testcafe-legacy-api": {
+			"version": "3.1.11",
+			"resolved": "https://registry.npmjs.org/testcafe-legacy-api/-/testcafe-legacy-api-3.1.11.tgz",
+			"integrity": "sha512-JWv8Exc9FAEBbKw+IP97Ebd+0FzA3nzgRv9iQCNh/+JlZyUox7NWiojs9BAXqgxIltl54rdo7TxPkNslxb+Ltw==",
+			"dev": true,
+			"requires": {
+				"async": "0.2.6",
+				"babel-runtime": "^5.8.34",
+				"dedent": "^0.6.0",
+				"highlight-es": "^1.0.0",
+				"is-jquery-obj": "^0.1.0",
+				"lodash": "^4.14.0",
+				"moment": "^2.14.1",
+				"mustache": "^2.2.1",
+				"os-family": "^1.0.0",
+				"parse5": "^2.1.5",
+				"pify": "^2.3.0",
+				"pinkie": "^2.0.1",
+				"strip-bom": "^2.0.0"
+			},
+			"dependencies": {
+				"babel-runtime": {
+					"version": "5.8.38",
+					"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
+					"integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=",
+					"dev": true,
+					"requires": {
+						"core-js": "^1.0.0"
+					}
+				},
+				"core-js": {
+					"version": "1.2.7",
+					"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
+					"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=",
+					"dev": true
+				},
+				"dedent": {
+					"version": "0.6.0",
+					"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz",
+					"integrity": "sha1-Dm2o8M5Sg471zsXI+TlrDBtko8s=",
+					"dev": true
+				},
+				"parse5": {
+					"version": "2.2.3",
+					"resolved": "https://registry.npmjs.org/parse5/-/parse5-2.2.3.tgz",
+					"integrity": "sha1-DE/EHBAAxea5PUiwP4CDg3g06fY=",
+					"dev": true
+				}
+			}
+		},
+		"testcafe-reporter-json": {
+			"version": "2.2.0",
+			"resolved": "https://registry.npmjs.org/testcafe-reporter-json/-/testcafe-reporter-json-2.2.0.tgz",
+			"integrity": "sha512-wfpNaZgGP2WoqdmnIXOyxcpwSzdH1HvzXSN397lJkXOrQrwhuGUThPDvyzPnZqxZSzXdDUvIPJm55tCMWbfymQ==",
+			"dev": true
+		},
+		"testcafe-reporter-list": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/testcafe-reporter-list/-/testcafe-reporter-list-2.1.0.tgz",
+			"integrity": "sha1-n6ifcbl9Pf5ktDAtXiJ97mmuxrk=",
+			"dev": true
+		},
+		"testcafe-reporter-minimal": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.1.0.tgz",
+			"integrity": "sha1-Z28DVHY0FDxurzq1KGgnOkvr9CE=",
+			"dev": true
+		},
+		"testcafe-reporter-spec": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/testcafe-reporter-spec/-/testcafe-reporter-spec-2.1.1.tgz",
+			"integrity": "sha1-gVb87Q9RMkhlWa1WC8gGdkaSdew=",
+			"dev": true
+		},
+		"testcafe-reporter-xunit": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.1.0.tgz",
+			"integrity": "sha1-5tZsVyzhWvJmcGrw/WELKoQd1EM=",
+			"dev": true
+		},
+		"time-limit-promise": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/time-limit-promise/-/time-limit-promise-1.0.4.tgz",
+			"integrity": "sha512-FLHDDsIDducw7MBcRWlFtW2Tm50DoKOSFf0Nzx17qwXj8REXCte0eUkHrJl9QU3Bl9arG3XNYX0PcHpZ9xyuLw==",
+			"dev": true
+		},
+		"tmp": {
+			"version": "0.0.28",
+			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz",
+			"integrity": "sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA=",
+			"dev": true,
+			"requires": {
+				"os-tmpdir": "~1.0.1"
+			}
+		},
+		"to-buffer": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
+			"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
+			"dev": true
+		},
+		"to-fast-properties": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+			"integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+			"dev": true
+		},
+		"to-object-path": {
+			"version": "0.3.0",
+			"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+			"integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+			"dev": true,
+			"requires": {
+				"kind-of": "^3.0.2"
+			},
+			"dependencies": {
+				"kind-of": {
+					"version": "3.2.2",
+					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+					"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+					"dev": true,
+					"requires": {
+						"is-buffer": "^1.1.5"
+					}
+				}
+			}
+		},
+		"to-regex": {
+			"version": "3.0.2",
+			"resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+			"integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+			"dev": true,
+			"requires": {
+				"define-property": "^2.0.2",
+				"extend-shallow": "^3.0.2",
+				"regex-not": "^1.0.2",
+				"safe-regex": "^1.1.0"
+			}
+		},
+		"to-regex-range": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+			"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+			"dev": true,
+			"requires": {
+				"is-number": "^3.0.0",
+				"repeat-string": "^1.6.1"
+			}
+		},
+		"tough-cookie": {
+			"version": "2.3.3",
+			"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
+			"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
+			"dev": true,
+			"requires": {
+				"punycode": "^1.4.1"
+			}
+		},
+		"tree-kill": {
+			"version": "1.2.1",
+			"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.1.tgz",
+			"integrity": "sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==",
+			"dev": true
+		},
+		"trim-right": {
+			"version": "1.0.1",
+			"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+			"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+			"dev": true
+		},
+		"truncate-utf8-bytes": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
+			"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
+			"dev": true,
+			"requires": {
+				"utf8-byte-length": "^1.0.1"
+			}
+		},
+		"tunnel-agent": {
+			"version": "0.6.0",
+			"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+			"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+			"dev": true,
+			"requires": {
+				"safe-buffer": "^5.0.1"
+			}
+		},
+		"tweetnacl": {
+			"version": "0.14.5",
+			"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+			"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+			"dev": true
+		},
+		"type-detect": {
+			"version": "4.0.8",
+			"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+			"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+			"dev": true
+		},
+		"typescript": {
+			"version": "3.5.2",
+			"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.2.tgz",
+			"integrity": "sha512-7KxJovlYhTX5RaRbUdkAXN1KUZ8PwWlTzQdHV6xNqvuFOs7+WBo10TQUqT19Q/Jz2hk5v9TQDIhyLhhJY4p5AA==",
+			"dev": true
+		},
+		"uglify-js": {
+			"version": "3.5.15",
+			"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.5.15.tgz",
+			"integrity": "sha512-fe7aYFotptIddkwcm6YuA0HmknBZ52ZzOsUxZEdhhkSsz7RfjHDX2QDxwKTiv4JQ5t5NhfmpgAK+J7LiDhKSqg==",
+			"dev": true,
+			"requires": {
+				"commander": "~2.20.0",
+				"source-map": "~0.6.1"
+			},
+			"dependencies": {
+				"source-map": {
+					"version": "0.6.1",
+					"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+					"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+					"dev": true
+				}
+			}
+		},
+		"ultron": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
+			"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
+			"dev": true
+		},
+		"unicode-canonical-property-names-ecmascript": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
+			"integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==",
+			"dev": true
+		},
+		"unicode-match-property-ecmascript": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
+			"integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
+			"dev": true,
+			"requires": {
+				"unicode-canonical-property-names-ecmascript": "^1.0.4",
+				"unicode-property-aliases-ecmascript": "^1.0.4"
+			}
+		},
+		"unicode-match-property-value-ecmascript": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz",
+			"integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==",
+			"dev": true
+		},
+		"unicode-property-aliases-ecmascript": {
+			"version": "1.0.5",
+			"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz",
+			"integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==",
+			"dev": true
+		},
+		"union-value": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
+			"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+			"dev": true,
+			"requires": {
+				"arr-union": "^3.1.0",
+				"get-value": "^2.0.6",
+				"is-extendable": "^0.1.1",
+				"set-value": "^0.4.3"
+			},
+			"dependencies": {
+				"extend-shallow": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+					"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+					"dev": true,
+					"requires": {
+						"is-extendable": "^0.1.0"
+					}
+				},
+				"set-value": {
+					"version": "0.4.3",
+					"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
+					"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
+					"dev": true,
+					"requires": {
+						"extend-shallow": "^2.0.1",
+						"is-extendable": "^0.1.1",
+						"is-plain-object": "^2.0.1",
+						"to-object-path": "^0.3.0"
+					}
+				}
+			}
+		},
+		"unset-value": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+			"integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+			"dev": true,
+			"requires": {
+				"has-value": "^0.3.1",
+				"isobject": "^3.0.0"
+			},
+			"dependencies": {
+				"has-value": {
+					"version": "0.3.1",
+					"resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+					"integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+					"dev": true,
+					"requires": {
+						"get-value": "^2.0.3",
+						"has-values": "^0.1.4",
+						"isobject": "^2.0.0"
+					},
+					"dependencies": {
+						"isobject": {
+							"version": "2.1.0",
+							"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+							"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+							"dev": true,
+							"requires": {
+								"isarray": "1.0.0"
+							}
+						}
+					}
+				},
+				"has-values": {
+					"version": "0.1.4",
+					"resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+					"integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+					"dev": true
+				}
+			}
+		},
+		"uri-js": {
+			"version": "4.2.2",
+			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+			"integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+			"dev": true,
+			"requires": {
+				"punycode": "^2.1.0"
+			},
+			"dependencies": {
+				"punycode": {
+					"version": "2.1.1",
+					"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+					"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+					"dev": true
+				}
+			}
+		},
+		"urix": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+			"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+			"dev": true
+		},
+		"use": {
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+			"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+			"dev": true
+		},
+		"useragent": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/useragent/-/useragent-2.3.0.tgz",
+			"integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
+			"dev": true,
+			"requires": {
+				"lru-cache": "4.1.x",
+				"tmp": "0.0.x"
+			},
+			"dependencies": {
+				"lru-cache": {
+					"version": "4.1.5",
+					"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+					"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+					"dev": true,
+					"requires": {
+						"pseudomap": "^1.0.2",
+						"yallist": "^2.1.2"
+					}
+				}
+			}
+		},
+		"utf8-byte-length": {
+			"version": "1.0.4",
+			"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
+			"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=",
+			"dev": true
+		},
+		"util-deprecate": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+			"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+			"dev": true
+		},
+		"uuid": {
+			"version": "3.3.2",
+			"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
+			"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
+			"dev": true
+		},
+		"vargs": {
+			"version": "0.1.0",
+			"resolved": "https://registry.npmjs.org/vargs/-/vargs-0.1.0.tgz",
+			"integrity": "sha1-a2GE2mUgzDIEzhtAfKwm2SYJ6/8=",
+			"dev": true
+		},
+		"verror": {
+			"version": "1.10.0",
+			"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+			"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+			"dev": true,
+			"requires": {
+				"assert-plus": "^1.0.0",
+				"core-util-is": "1.0.2",
+				"extsprintf": "^1.2.0"
+			}
+		},
+		"wd": {
+			"version": "1.11.2",
+			"resolved": "https://registry.npmjs.org/wd/-/wd-1.11.2.tgz",
+			"integrity": "sha512-zXJY9ARjQQYN2LatLTRcW39EYzIVqKNhGpp4XWJmRgHBioG4FoenIOsoVbaO8lnFGgv31V99kAy5hB4eWGIwzA==",
+			"dev": true,
+			"requires": {
+				"archiver": "2.1.1",
+				"async": "2.0.1",
+				"lodash": "4.17.11",
+				"mkdirp": "^0.5.1",
+				"q": "1.4.1",
+				"request": "2.88.0",
+				"vargs": "0.1.0"
+			},
+			"dependencies": {
+				"async": {
+					"version": "2.0.1",
+					"resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz",
+					"integrity": "sha1-twnMAoCpw28J9FNr6CPIOKkEniU=",
+					"dev": true,
+					"requires": {
+						"lodash": "^4.8.0"
+					}
+				}
+			}
+		},
+		"webauth": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/webauth/-/webauth-1.1.0.tgz",
+			"integrity": "sha1-ZHBPa4AmmGYFvDymKZUubib90QA=",
+			"dev": true
+		},
+		"which": {
+			"version": "1.3.1",
+			"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+			"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+			"dev": true,
+			"requires": {
+				"isexe": "^2.0.0"
+			}
+		},
+		"which-promise": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/which-promise/-/which-promise-1.0.0.tgz",
+			"integrity": "sha1-ILch3wWzW3Bhdv+hCwkJq6RgMDU=",
+			"dev": true,
+			"requires": {
+				"pify": "^2.2.0",
+				"pinkie-promise": "^1.0.0",
+				"which": "^1.1.2"
+			},
+			"dependencies": {
+				"pinkie": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz",
+					"integrity": "sha1-Wkfyi6EBXQIBvae/DzWOR77Ix+Q=",
+					"dev": true
+				},
+				"pinkie-promise": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz",
+					"integrity": "sha1-0dpn9UglY7t89X8oauKCLs+/NnA=",
+					"dev": true,
+					"requires": {
+						"pinkie": "^1.0.0"
+					}
+				}
+			}
+		},
+		"wrap-ansi": {
+			"version": "2.1.0",
+			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+			"integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+			"dev": true,
+			"requires": {
+				"string-width": "^1.0.1",
+				"strip-ansi": "^3.0.1"
+			}
+		},
+		"wrappy": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+			"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+			"dev": true
+		},
+		"ws": {
+			"version": "3.3.3",
+			"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
+			"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
+			"dev": true,
+			"requires": {
+				"async-limiter": "~1.0.0",
+				"safe-buffer": "~5.1.0",
+				"ultron": "~1.1.0"
+			}
+		},
+		"xtend": {
+			"version": "4.0.1",
+			"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+			"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+			"dev": true
+		},
+		"yallist": {
+			"version": "2.1.2",
+			"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+			"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
+			"dev": true
+		},
+		"zip-stream": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz",
+			"integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=",
+			"dev": true,
+			"requires": {
+				"archiver-utils": "^1.3.0",
+				"compress-commons": "^1.2.0",
+				"lodash": "^4.8.0",
+				"readable-stream": "^2.0.0"
+			}
+		}
+	}
+}

+ 56 - 0
public/assets/libs/Sortable/package.json

@@ -0,0 +1,56 @@
+{
+	"name": "sortablejs",
+	"exportName": "Sortable",
+	"version": "1.10.2",
+	"devDependencies": {
+		"@babel/core": "^7.4.4",
+		"@babel/plugin-transform-object-assign": "^7.2.0",
+		"@babel/preset-env": "^7.4.4",
+		"rollup": "^1.11.3",
+		"rollup-plugin-babel": "^4.3.2",
+		"rollup-plugin-json": "^4.0.0",
+		"rollup-plugin-node-resolve": "^5.0.0",
+		"testcafe": "^1.3.1",
+		"testcafe-browser-provider-saucelabs": "^1.7.0",
+		"testcafe-reporter-xunit": "^2.1.0",
+		"uglify-js": "^3.5.12"
+	},
+	"description": "JavaScript library for reorderable drag-and-drop lists on modern browsers and touch devices. No jQuery required. Supports Meteor, AngularJS, React, Polymer, Vue, Knockout and any CSS library, e.g. Bootstrap.",
+	"main": "./Sortable.js",
+	"module": "modular/sortable.esm.js",
+	"scripts": {
+		"build:umd": "NODE_ENV=umd rollup -c ./scripts/umd-build.js",
+		"build:umd:watch": "set NODE_ENV=umd&& rollup -w -c ./scripts/umd-build.js",
+		"build:es": "set NODE_ENV=es&& rollup -c ./scripts/esm-build.js",
+		"build:es:watch": "set NODE_ENV=es&& rollup -w -c ./scripts/esm-build.js",
+		"minify": "node ./scripts/minify.js",
+		"build": "npm run build:es && npm run build:umd && npm run minify",
+		"test:compat": "node ./scripts/test-compat.js",
+		"test": "node ./scripts/test.js"
+	},
+	"maintainers": [
+		"Konstantin Lebedev <ibnRubaXa@gmail.com>",
+		"Owen Mills <owen23355@gmail.com>"
+	],
+	"repository": {
+		"type": "git",
+		"url": "git://github.com/SortableJS/Sortable.git"
+	},
+	"files": [
+		"Sortable.js",
+		"Sortable.min.js",
+		"modular/"
+	],
+	"keywords": [
+		"sortable",
+		"reorder",
+		"drag",
+		"meteor",
+		"angular",
+		"ng-sortable",
+		"react",
+		"vue",
+		"mixin"
+	],
+	"license": "MIT"
+}

+ 270 - 0
public/assets/libs/Sortable/plugins/AutoScroll/AutoScroll.js

@@ -0,0 +1,270 @@
+import {
+	on,
+	off,
+	css,
+	throttle,
+	cancelThrottle,
+	scrollBy,
+	getParentAutoScrollElement,
+	expando,
+	getRect,
+	getWindowScrollingElement
+} from '../../src/utils.js';
+
+import Sortable from '../../src/Sortable.js';
+
+import { Edge, IE11OrLess, Safari } from '../../src/BrowserInfo.js';
+
+let autoScrolls = [],
+	scrollEl,
+	scrollRootEl,
+	scrolling = false,
+	lastAutoScrollX,
+	lastAutoScrollY,
+	touchEvt,
+	pointerElemChangedInterval;
+
+function AutoScrollPlugin() {
+
+	function AutoScroll() {
+		this.defaults = {
+			scroll: true,
+			scrollSensitivity: 30,
+			scrollSpeed: 10,
+			bubbleScroll: true
+		};
+
+		// Bind all private methods
+		for (let fn in this) {
+			if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+				this[fn] = this[fn].bind(this);
+			}
+		}
+	}
+
+	AutoScroll.prototype = {
+		dragStarted({ originalEvent }) {
+			if (this.sortable.nativeDraggable) {
+				on(document, 'dragover', this._handleAutoScroll);
+			} else {
+				if (this.options.supportPointer) {
+					on(document, 'pointermove', this._handleFallbackAutoScroll);
+				} else if (originalEvent.touches) {
+					on(document, 'touchmove', this._handleFallbackAutoScroll);
+				} else {
+					on(document, 'mousemove', this._handleFallbackAutoScroll);
+				}
+			}
+		},
+
+		dragOverCompleted({ originalEvent }) {
+			// For when bubbling is canceled and using fallback (fallback 'touchmove' always reached)
+			if (!this.options.dragOverBubble && !originalEvent.rootEl) {
+				this._handleAutoScroll(originalEvent);
+			}
+		},
+
+		drop() {
+			if (this.sortable.nativeDraggable) {
+				off(document, 'dragover', this._handleAutoScroll);
+			} else {
+				off(document, 'pointermove', this._handleFallbackAutoScroll);
+				off(document, 'touchmove', this._handleFallbackAutoScroll);
+				off(document, 'mousemove', this._handleFallbackAutoScroll);
+			}
+
+			clearPointerElemChangedInterval();
+			clearAutoScrolls();
+			cancelThrottle();
+		},
+
+		nulling() {
+			touchEvt =
+			scrollRootEl =
+			scrollEl =
+			scrolling =
+			pointerElemChangedInterval =
+			lastAutoScrollX =
+			lastAutoScrollY = null;
+
+			autoScrolls.length = 0;
+		},
+
+		_handleFallbackAutoScroll(evt) {
+			this._handleAutoScroll(evt, true);
+		},
+
+		_handleAutoScroll(evt, fallback) {
+			const x = (evt.touches ? evt.touches[0] : evt).clientX,
+				y = (evt.touches ? evt.touches[0] : evt).clientY,
+
+				elem = document.elementFromPoint(x, y);
+
+			touchEvt = evt;
+
+			// IE does not seem to have native autoscroll,
+			// Edge's autoscroll seems too conditional,
+			// MACOS Safari does not have autoscroll,
+			// Firefox and Chrome are good
+			if (fallback || Edge || IE11OrLess || Safari) {
+				autoScroll(evt, this.options, elem, fallback);
+
+				// Listener for pointer element change
+				let ogElemScroller = getParentAutoScrollElement(elem, true);
+				if (
+					scrolling &&
+					(
+						!pointerElemChangedInterval ||
+						x !== lastAutoScrollX ||
+						y !== lastAutoScrollY
+					)
+				) {
+					pointerElemChangedInterval && clearPointerElemChangedInterval();
+					// Detect for pointer elem change, emulating native DnD behaviour
+					pointerElemChangedInterval = setInterval(() => {
+						let newElem = getParentAutoScrollElement(document.elementFromPoint(x, y), true);
+						if (newElem !== ogElemScroller) {
+							ogElemScroller = newElem;
+							clearAutoScrolls();
+						}
+						autoScroll(evt, this.options, newElem, fallback);
+					}, 10);
+					lastAutoScrollX = x;
+					lastAutoScrollY = y;
+				}
+			} else {
+				// if DnD is enabled (and browser has good autoscrolling), first autoscroll will already scroll, so get parent autoscroll of first autoscroll
+				if (!this.options.bubbleScroll || getParentAutoScrollElement(elem, true) === getWindowScrollingElement()) {
+					clearAutoScrolls();
+					return;
+				}
+				autoScroll(evt, this.options, getParentAutoScrollElement(elem, false), false);
+			}
+		}
+	};
+
+	return Object.assign(AutoScroll, {
+		pluginName: 'scroll',
+		initializeByDefault: true
+	});
+}
+
+function clearAutoScrolls() {
+	autoScrolls.forEach(function(autoScroll) {
+		clearInterval(autoScroll.pid);
+	});
+	autoScrolls = [];
+}
+
+function clearPointerElemChangedInterval() {
+	clearInterval(pointerElemChangedInterval);
+}
+
+
+const autoScroll = throttle(function(evt, options, rootEl, isFallback) {
+	// Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=505521
+	if (!options.scroll) return;
+	const x = (evt.touches ? evt.touches[0] : evt).clientX,
+		y = (evt.touches ? evt.touches[0] : evt).clientY,
+		sens = options.scrollSensitivity,
+		speed = options.scrollSpeed,
+		winScroller = getWindowScrollingElement();
+
+	let scrollThisInstance = false,
+		scrollCustomFn;
+
+	// New scroll root, set scrollEl
+	if (scrollRootEl !== rootEl) {
+		scrollRootEl = rootEl;
+
+		clearAutoScrolls();
+
+		scrollEl = options.scroll;
+		scrollCustomFn = options.scrollFn;
+
+		if (scrollEl === true) {
+			scrollEl = getParentAutoScrollElement(rootEl, true);
+		}
+	}
+
+
+	let layersOut = 0;
+	let currentParent = scrollEl;
+	do {
+		let	el = currentParent,
+			rect = getRect(el),
+
+			top = rect.top,
+			bottom = rect.bottom,
+			left = rect.left,
+			right = rect.right,
+
+			width = rect.width,
+			height = rect.height,
+
+			canScrollX,
+			canScrollY,
+
+			scrollWidth = el.scrollWidth,
+			scrollHeight = el.scrollHeight,
+
+			elCSS = css(el),
+
+			scrollPosX = el.scrollLeft,
+			scrollPosY = el.scrollTop;
+
+
+		if (el === winScroller) {
+			canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll' || elCSS.overflowX === 'visible');
+			canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll' || elCSS.overflowY === 'visible');
+		} else {
+			canScrollX = width < scrollWidth && (elCSS.overflowX === 'auto' || elCSS.overflowX === 'scroll');
+			canScrollY = height < scrollHeight && (elCSS.overflowY === 'auto' || elCSS.overflowY === 'scroll');
+		}
+
+		let vx = canScrollX && (Math.abs(right - x) <= sens && (scrollPosX + width) < scrollWidth) - (Math.abs(left - x) <= sens && !!scrollPosX);
+		let vy = canScrollY && (Math.abs(bottom - y) <= sens && (scrollPosY + height) < scrollHeight) - (Math.abs(top - y) <= sens && !!scrollPosY);
+
+
+		if (!autoScrolls[layersOut]) {
+			for (let i = 0; i <= layersOut; i++) {
+				if (!autoScrolls[i]) {
+					autoScrolls[i] = {};
+				}
+			}
+		}
+
+		if (autoScrolls[layersOut].vx != vx || autoScrolls[layersOut].vy != vy || autoScrolls[layersOut].el !== el) {
+			autoScrolls[layersOut].el = el;
+			autoScrolls[layersOut].vx = vx;
+			autoScrolls[layersOut].vy = vy;
+
+			clearInterval(autoScrolls[layersOut].pid);
+
+			if (vx != 0 || vy != 0) {
+				scrollThisInstance = true;
+				/* jshint loopfunc:true */
+				autoScrolls[layersOut].pid = setInterval((function () {
+					// emulate drag over during autoscroll (fallback), emulating native DnD behaviour
+					if (isFallback && this.layer === 0) {
+						Sortable.active._onTouchMove(touchEvt); // To move ghost if it is positioned absolutely
+					}
+					let scrollOffsetY = autoScrolls[this.layer].vy ? autoScrolls[this.layer].vy * speed : 0;
+					let scrollOffsetX = autoScrolls[this.layer].vx ? autoScrolls[this.layer].vx * speed : 0;
+
+					if (typeof(scrollCustomFn) === 'function') {
+						if (scrollCustomFn.call(Sortable.dragged.parentNode[expando], scrollOffsetX, scrollOffsetY, evt, touchEvt, autoScrolls[this.layer].el) !== 'continue') {
+							return;
+						}
+					}
+
+					scrollBy(autoScrolls[this.layer].el, scrollOffsetX, scrollOffsetY);
+				}).bind({layer: layersOut}), 24);
+			}
+		}
+		layersOut++;
+	} while (options.bubbleScroll && currentParent !== winScroller && (currentParent = getParentAutoScrollElement(currentParent, false)));
+	scrolling = scrollThisInstance; // in case another function catches scrolling as false in between when it is not
+}, 30);
+
+export default AutoScrollPlugin;

+ 80 - 0
public/assets/libs/Sortable/plugins/AutoScroll/README.md

@@ -0,0 +1,80 @@
+## AutoScroll
+This plugin allows for the page to automatically scroll during dragging near a scrollable element's edge on mobile devices and IE9 (or whenever fallback is enabled), and also enhances most browser's native drag-and-drop autoscrolling.
+Demo:
+ - `window`: https://jsbin.com/dosilir/edit?js,output
+ - `overflow: hidden`: https://jsbin.com/xecihez/edit?html,js,output
+
+**This plugin is a default plugin, and is included in the default UMD and ESM builds of Sortable**
+
+
+---
+
+
+### Mounting
+```js
+import { Sortable, AutoScroll } from 'sortablejs';
+
+Sortable.mount(new AutoScroll());
+```
+
+
+---
+
+
+### Options
+
+```js
+new Sortable(el, {
+	scroll: true, // Enable the plugin. Can be HTMLElement.
+	scrollFn: function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { ... }, // if you have custom scrollbar scrollFn may be used for autoscrolling
+	scrollSensitivity: 30, // px, how near the mouse must be to an edge to start scrolling.
+	scrollSpeed: 10, // px, speed of the scrolling
+	bubbleScroll: true // apply autoscroll to all parent elements, allowing for easier movement
+});
+```
+
+
+---
+
+
+#### `scroll` option
+Enables the plugin. Defaults to `true`. May also be set to an HTMLElement which will be where autoscrolling is rooted.
+
+Demo:
+ - `window`: https://jsbin.com/dosilir/edit?js,output
+ - `overflow: hidden`: https://jsbin.com/xecihez/edit?html,js,output
+
+
+---
+
+
+#### `scrollFn` option
+Defines function that will be used for autoscrolling. el.scrollTop/el.scrollLeft is used by default.
+Useful when you have custom scrollbar with dedicated scroll function.
+This function should return `'continue'` if it wishes to allow Sortable's native autoscrolling.
+
+
+---
+
+
+#### `scrollSensitivity` option
+Defines how near the mouse must be to an edge to start scrolling.
+
+
+---
+
+
+#### `scrollSpeed` option
+The speed at which the window should scroll once the mouse pointer gets within the `scrollSensitivity` distance.
+
+
+---
+
+
+#### `bubbleScroll` option
+If set to `true`, the normal `autoscroll` function will also be applied to all parent elements of the element the user is dragging over.
+
+Demo: https://jsbin.com/kesewor/edit?html,js,output
+
+
+---

+ 1 - 0
public/assets/libs/Sortable/plugins/AutoScroll/index.js

@@ -0,0 +1 @@
+export { default } from './AutoScroll.js';

+ 617 - 0
public/assets/libs/Sortable/plugins/MultiDrag/MultiDrag.js

@@ -0,0 +1,617 @@
+import {
+	toggleClass,
+	getRect,
+	index,
+	closest,
+	on,
+	off,
+	clone,
+	css,
+	setRect,
+	unsetRect,
+	matrix,
+	expando
+} from '../../src/utils.js';
+
+import dispatchEvent from '../../src/EventDispatcher.js';
+
+let multiDragElements = [],
+	multiDragClones = [],
+	lastMultiDragSelect, // for selection with modifier key down (SHIFT)
+	multiDragSortable,
+	initialFolding = false, // Initial multi-drag fold when drag started
+	folding = false, // Folding any other time
+	dragStarted = false,
+	dragEl,
+	clonesFromRect,
+	clonesHidden;
+
+function MultiDragPlugin() {
+	function MultiDrag(sortable) {
+		// Bind all private methods
+		for (let fn in this) {
+			if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+				this[fn] = this[fn].bind(this);
+			}
+		}
+
+		if (sortable.options.supportPointer) {
+			on(document, 'pointerup', this._deselectMultiDrag);
+		} else {
+			on(document, 'mouseup', this._deselectMultiDrag);
+			on(document, 'touchend', this._deselectMultiDrag);
+		}
+
+		on(document, 'keydown', this._checkKeyDown);
+		on(document, 'keyup', this._checkKeyUp);
+
+		this.defaults = {
+			selectedClass: 'sortable-selected',
+			multiDragKey: null,
+			setData(dataTransfer, dragEl) {
+				let data = '';
+				if (multiDragElements.length && multiDragSortable === sortable) {
+					multiDragElements.forEach((multiDragElement, i) => {
+						data += (!i ? '' : ', ') + multiDragElement.textContent;
+					});
+				} else {
+					data = dragEl.textContent;
+				}
+				dataTransfer.setData('Text', data);
+			}
+		};
+	}
+
+	MultiDrag.prototype = {
+		multiDragKeyDown: false,
+		isMultiDrag: false,
+
+
+		delayStartGlobal({ dragEl: dragged }) {
+			dragEl = dragged;
+		},
+
+		delayEnded() {
+			this.isMultiDrag = ~multiDragElements.indexOf(dragEl);
+		},
+
+		setupClone({ sortable, cancel }) {
+			if (!this.isMultiDrag) return;
+			for (let i = 0; i < multiDragElements.length; i++) {
+				multiDragClones.push(clone(multiDragElements[i]));
+
+				multiDragClones[i].sortableIndex = multiDragElements[i].sortableIndex;
+
+				multiDragClones[i].draggable = false;
+				multiDragClones[i].style['will-change'] = '';
+
+				toggleClass(multiDragClones[i], this.options.selectedClass, false);
+				multiDragElements[i] === dragEl && toggleClass(multiDragClones[i], this.options.chosenClass, false);
+			}
+
+			sortable._hideClone();
+			cancel();
+		},
+
+		clone({ sortable, rootEl, dispatchSortableEvent, cancel }) {
+			if (!this.isMultiDrag) return;
+			if (!this.options.removeCloneOnHide) {
+				if (multiDragElements.length && multiDragSortable === sortable) {
+					insertMultiDragClones(true, rootEl);
+					dispatchSortableEvent('clone');
+
+					cancel();
+				}
+			}
+		},
+
+		showClone({ cloneNowShown, rootEl, cancel }) {
+			if (!this.isMultiDrag) return;
+			insertMultiDragClones(false, rootEl);
+			multiDragClones.forEach(clone => {
+				css(clone, 'display', '');
+			});
+
+			cloneNowShown();
+			clonesHidden = false;
+			cancel();
+		},
+
+		hideClone({ sortable, cloneNowHidden, cancel }) {
+			if (!this.isMultiDrag) return;
+			multiDragClones.forEach(clone => {
+				css(clone, 'display', 'none');
+				if (this.options.removeCloneOnHide && clone.parentNode) {
+					clone.parentNode.removeChild(clone);
+				}
+			});
+
+			cloneNowHidden();
+			clonesHidden = true;
+			cancel();
+		},
+
+		dragStartGlobal({ sortable }) {
+			if (!this.isMultiDrag && multiDragSortable) {
+				multiDragSortable.multiDrag._deselectMultiDrag();
+			}
+
+			multiDragElements.forEach(multiDragElement => {
+				multiDragElement.sortableIndex = index(multiDragElement);
+			});
+
+			// Sort multi-drag elements
+			multiDragElements = multiDragElements.sort(function(a, b) {
+				return a.sortableIndex - b.sortableIndex;
+			});
+			dragStarted = true;
+		},
+
+		dragStarted({ sortable }) {
+			if (!this.isMultiDrag) return;
+			if (this.options.sort) {
+				// Capture rects,
+				// hide multi drag elements (by positioning them absolute),
+				// set multi drag elements rects to dragRect,
+				// show multi drag elements,
+				// animate to rects,
+				// unset rects & remove from DOM
+
+				sortable.captureAnimationState();
+
+				if (this.options.animation) {
+					multiDragElements.forEach(multiDragElement => {
+						if (multiDragElement === dragEl) return;
+						css(multiDragElement, 'position', 'absolute');
+					});
+
+					let dragRect = getRect(dragEl, false, true, true);
+
+					multiDragElements.forEach(multiDragElement => {
+						if (multiDragElement === dragEl) return;
+						setRect(multiDragElement, dragRect);
+					});
+
+					folding = true;
+					initialFolding = true;
+				}
+			}
+
+			sortable.animateAll(() => {
+				folding = false;
+				initialFolding = false;
+
+				if (this.options.animation) {
+					multiDragElements.forEach(multiDragElement => {
+						unsetRect(multiDragElement);
+					});
+				}
+
+				// Remove all auxiliary multidrag items from el, if sorting enabled
+				if (this.options.sort) {
+					removeMultiDragElements();
+				}
+			});
+		},
+
+		dragOver({ target, completed, cancel }) {
+			if (folding && ~multiDragElements.indexOf(target)) {
+				completed(false);
+				cancel();
+			}
+		},
+
+		revert({ fromSortable, rootEl, sortable, dragRect }) {
+			if (multiDragElements.length > 1) {
+				// Setup unfold animation
+				multiDragElements.forEach(multiDragElement => {
+					sortable.addAnimationState({
+						target: multiDragElement,
+						rect: folding ? getRect(multiDragElement) : dragRect
+					});
+
+					unsetRect(multiDragElement);
+
+					multiDragElement.fromRect = dragRect;
+
+					fromSortable.removeAnimationState(multiDragElement);
+				});
+				folding = false;
+				insertMultiDragElements(!this.options.removeCloneOnHide, rootEl);
+			}
+		},
+
+		dragOverCompleted({ sortable, isOwner, insertion, activeSortable, parentEl, putSortable }) {
+			let options = this.options;
+			if (insertion) {
+				// Clones must be hidden before folding animation to capture dragRectAbsolute properly
+				if (isOwner) {
+					activeSortable._hideClone();
+				}
+
+				initialFolding = false;
+				// If leaving sort:false root, or already folding - Fold to new location
+				if (options.animation && multiDragElements.length > 1 && (folding || !isOwner && !activeSortable.options.sort && !putSortable)) {
+					// Fold: Set all multi drag elements's rects to dragEl's rect when multi-drag elements are invisible
+					let dragRectAbsolute = getRect(dragEl, false, true, true);
+
+					multiDragElements.forEach(multiDragElement => {
+						if (multiDragElement === dragEl) return;
+						setRect(multiDragElement, dragRectAbsolute);
+
+						// Move element(s) to end of parentEl so that it does not interfere with multi-drag clones insertion if they are inserted
+						// while folding, and so that we can capture them again because old sortable will no longer be fromSortable
+						parentEl.appendChild(multiDragElement);
+					});
+
+					folding = true;
+				}
+
+				// Clones must be shown (and check to remove multi drags) after folding when interfering multiDragElements are moved out
+				if (!isOwner) {
+					// Only remove if not folding (folding will remove them anyways)
+					if (!folding) {
+						removeMultiDragElements();
+					}
+
+					if (multiDragElements.length > 1) {
+						let clonesHiddenBefore = clonesHidden;
+						activeSortable._showClone(sortable);
+
+						// Unfold animation for clones if showing from hidden
+						if (activeSortable.options.animation && !clonesHidden && clonesHiddenBefore) {
+							multiDragClones.forEach(clone => {
+								activeSortable.addAnimationState({
+									target: clone,
+									rect: clonesFromRect
+								});
+
+								clone.fromRect = clonesFromRect;
+								clone.thisAnimationDuration = null;
+							});
+						}
+					} else {
+						activeSortable._showClone(sortable);
+					}
+				}
+			}
+		},
+
+		dragOverAnimationCapture({ dragRect, isOwner, activeSortable }) {
+			multiDragElements.forEach(multiDragElement => {
+				multiDragElement.thisAnimationDuration = null;
+			});
+
+			if (activeSortable.options.animation && !isOwner && activeSortable.multiDrag.isMultiDrag) {
+				clonesFromRect = Object.assign({}, dragRect);
+				let dragMatrix = matrix(dragEl, true);
+				clonesFromRect.top -= dragMatrix.f;
+				clonesFromRect.left -= dragMatrix.e;
+			}
+		},
+
+		dragOverAnimationComplete() {
+			if (folding) {
+				folding = false;
+				removeMultiDragElements();
+			}
+		},
+
+		drop({ originalEvent: evt, rootEl, parentEl, sortable, dispatchSortableEvent, oldIndex, putSortable }) {
+			let toSortable = (putSortable || this.sortable);
+
+			if (!evt) return;
+
+			let options = this.options,
+				children = parentEl.children;
+
+			// Multi-drag selection
+			if (!dragStarted) {
+				if (options.multiDragKey && !this.multiDragKeyDown) {
+					this._deselectMultiDrag();
+				}
+				toggleClass(dragEl, options.selectedClass, !~multiDragElements.indexOf(dragEl));
+
+				if (!~multiDragElements.indexOf(dragEl)) {
+					multiDragElements.push(dragEl);
+					dispatchEvent({
+						sortable,
+						rootEl,
+						name: 'select',
+						targetEl: dragEl,
+						originalEvt: evt
+					});
+
+					// Modifier activated, select from last to dragEl
+					if (evt.shiftKey && lastMultiDragSelect && sortable.el.contains(lastMultiDragSelect)) {
+						let lastIndex = index(lastMultiDragSelect),
+							currentIndex = index(dragEl);
+
+						if (~lastIndex && ~currentIndex && lastIndex !== currentIndex) {
+							// Must include lastMultiDragSelect (select it), in case modified selection from no selection
+							// (but previous selection existed)
+							let n, i;
+							if (currentIndex > lastIndex) {
+								i = lastIndex;
+								n = currentIndex;
+							} else {
+								i = currentIndex;
+								n = lastIndex + 1;
+							}
+
+							for (; i < n; i++) {
+								if (~multiDragElements.indexOf(children[i])) continue;
+								toggleClass(children[i], options.selectedClass, true);
+								multiDragElements.push(children[i]);
+
+								dispatchEvent({
+									sortable,
+									rootEl,
+									name: 'select',
+									targetEl: children[i],
+									originalEvt: evt
+								});
+							}
+						}
+					} else {
+						lastMultiDragSelect = dragEl;
+					}
+
+					multiDragSortable = toSortable;
+				} else {
+					multiDragElements.splice(multiDragElements.indexOf(dragEl), 1);
+					lastMultiDragSelect = null;
+					dispatchEvent({
+						sortable,
+						rootEl,
+						name: 'deselect',
+						targetEl: dragEl,
+						originalEvt: evt
+					});
+				}
+			}
+
+			// Multi-drag drop
+			if (dragStarted && this.isMultiDrag) {
+				// Do not "unfold" after around dragEl if reverted
+				if ((parentEl[expando].options.sort || parentEl !== rootEl) && multiDragElements.length > 1) {
+					let dragRect = getRect(dragEl),
+						multiDragIndex = index(dragEl, ':not(.' + this.options.selectedClass + ')');
+
+					if (!initialFolding && options.animation) dragEl.thisAnimationDuration = null;
+
+					toSortable.captureAnimationState();
+
+					if (!initialFolding) {
+						if (options.animation) {
+							dragEl.fromRect = dragRect;
+							multiDragElements.forEach(multiDragElement => {
+								multiDragElement.thisAnimationDuration = null;
+								if (multiDragElement !== dragEl) {
+									let rect = folding ? getRect(multiDragElement) : dragRect;
+									multiDragElement.fromRect = rect;
+
+									// Prepare unfold animation
+									toSortable.addAnimationState({
+										target: multiDragElement,
+										rect: rect
+									});
+								}
+							});
+						}
+
+						// Multi drag elements are not necessarily removed from the DOM on drop, so to reinsert
+						// properly they must all be removed
+						removeMultiDragElements();
+
+						multiDragElements.forEach(multiDragElement => {
+							if (children[multiDragIndex]) {
+								parentEl.insertBefore(multiDragElement, children[multiDragIndex]);
+							} else {
+								parentEl.appendChild(multiDragElement);
+							}
+							multiDragIndex++;
+						});
+
+						// If initial folding is done, the elements may have changed position because they are now
+						// unfolding around dragEl, even though dragEl may not have his index changed, so update event
+						// must be fired here as Sortable will not.
+						if (oldIndex === index(dragEl)) {
+							let update = false;
+							multiDragElements.forEach(multiDragElement => {
+								if (multiDragElement.sortableIndex !== index(multiDragElement)) {
+									update = true;
+									return;
+								}
+							});
+
+							if (update) {
+								dispatchSortableEvent('update');
+							}
+						}
+					}
+
+					// Must be done after capturing individual rects (scroll bar)
+					multiDragElements.forEach(multiDragElement => {
+						unsetRect(multiDragElement);
+					});
+
+					toSortable.animateAll();
+				}
+
+				multiDragSortable = toSortable;
+			}
+
+			// Remove clones if necessary
+			if (rootEl === parentEl || (putSortable && putSortable.lastPutMode !== 'clone')) {
+				multiDragClones.forEach(clone => {
+					clone.parentNode && clone.parentNode.removeChild(clone);
+				});
+			}
+		},
+
+		nullingGlobal() {
+			this.isMultiDrag =
+			dragStarted = false;
+			multiDragClones.length = 0;
+		},
+
+		destroyGlobal() {
+			this._deselectMultiDrag();
+			off(document, 'pointerup', this._deselectMultiDrag);
+			off(document, 'mouseup', this._deselectMultiDrag);
+			off(document, 'touchend', this._deselectMultiDrag);
+
+			off(document, 'keydown', this._checkKeyDown);
+			off(document, 'keyup', this._checkKeyUp);
+		},
+
+		_deselectMultiDrag(evt) {
+			if (typeof dragStarted !== "undefined" && dragStarted) return;
+
+			// Only deselect if selection is in this sortable
+			if (multiDragSortable !== this.sortable) return;
+
+			// Only deselect if target is not item in this sortable
+			if (evt && closest(evt.target, this.options.draggable, this.sortable.el, false)) return;
+
+			// Only deselect if left click
+			if (evt && evt.button !== 0) return;
+
+			while (multiDragElements.length) {
+				let el = multiDragElements[0];
+				toggleClass(el, this.options.selectedClass, false);
+				multiDragElements.shift();
+				dispatchEvent({
+					sortable: this.sortable,
+					rootEl: this.sortable.el,
+					name: 'deselect',
+					targetEl: el,
+					originalEvt: evt
+				});
+			}
+		},
+
+		_checkKeyDown(evt) {
+			if (evt.key === this.options.multiDragKey) {
+				this.multiDragKeyDown = true;
+			}
+		},
+
+		_checkKeyUp(evt) {
+			if (evt.key === this.options.multiDragKey) {
+				this.multiDragKeyDown = false;
+			}
+		}
+	};
+
+	return Object.assign(MultiDrag, {
+		// Static methods & properties
+		pluginName: 'multiDrag',
+		utils: {
+			/**
+			 * Selects the provided multi-drag item
+			 * @param  {HTMLElement} el    The element to be selected
+			 */
+			select(el) {
+				let sortable = el.parentNode[expando];
+				if (!sortable || !sortable.options.multiDrag || ~multiDragElements.indexOf(el)) return;
+				if (multiDragSortable && multiDragSortable !== sortable) {
+					multiDragSortable.multiDrag._deselectMultiDrag();
+					multiDragSortable = sortable;
+				}
+				toggleClass(el, sortable.options.selectedClass, true);
+				multiDragElements.push(el);
+			},
+			/**
+			 * Deselects the provided multi-drag item
+			 * @param  {HTMLElement} el    The element to be deselected
+			 */
+			deselect(el) {
+				let sortable = el.parentNode[expando],
+					index = multiDragElements.indexOf(el);
+				if (!sortable || !sortable.options.multiDrag || !~index) return;
+				toggleClass(el, sortable.options.selectedClass, false);
+				multiDragElements.splice(index, 1);
+			}
+		},
+		eventProperties() {
+			const oldIndicies = [],
+				newIndicies = [];
+
+			multiDragElements.forEach(multiDragElement => {
+				oldIndicies.push({
+					multiDragElement,
+					index: multiDragElement.sortableIndex
+				});
+
+				// multiDragElements will already be sorted if folding
+				let newIndex;
+				if (folding && multiDragElement !== dragEl) {
+					newIndex = -1;
+				} else if (folding) {
+					newIndex = index(multiDragElement, ':not(.' + this.options.selectedClass + ')');
+				} else {
+					newIndex = index(multiDragElement);
+				}
+				newIndicies.push({
+					multiDragElement,
+					index: newIndex
+				});
+			});
+			return {
+				items: [...multiDragElements],
+				clones: [...multiDragClones],
+				oldIndicies,
+				newIndicies
+			};
+		},
+		optionListeners: {
+			multiDragKey(key) {
+				key = key.toLowerCase();
+				if (key === 'ctrl') {
+					key = 'Control';
+				} else if (key.length > 1) {
+					key = key.charAt(0).toUpperCase() + key.substr(1);
+				}
+				return key;
+			}
+		}
+	});
+}
+
+function insertMultiDragElements(clonesInserted, rootEl) {
+	multiDragElements.forEach((multiDragElement, i) => {
+		let target = rootEl.children[multiDragElement.sortableIndex + (clonesInserted ? Number(i) : 0)];
+		if (target) {
+			rootEl.insertBefore(multiDragElement, target);
+		} else {
+			rootEl.appendChild(multiDragElement);
+		}
+	});
+}
+
+/**
+ * Insert multi-drag clones
+ * @param  {[Boolean]} elementsInserted  Whether the multi-drag elements are inserted
+ * @param  {HTMLElement} rootEl
+ */
+function insertMultiDragClones(elementsInserted, rootEl) {
+	multiDragClones.forEach((clone, i) => {
+		let target = rootEl.children[clone.sortableIndex + (elementsInserted ? Number(i) : 0)];
+		if (target) {
+			rootEl.insertBefore(clone, target);
+		} else {
+			rootEl.appendChild(clone);
+		}
+	});
+}
+
+function removeMultiDragElements() {
+	multiDragElements.forEach(multiDragElement => {
+		if (multiDragElement === dragEl) return;
+		multiDragElement.parentNode && multiDragElement.parentNode.removeChild(multiDragElement);
+	});
+}
+
+export default MultiDragPlugin;

+ 96 - 0
public/assets/libs/Sortable/plugins/MultiDrag/README.md

@@ -0,0 +1,96 @@
+## MultiDrag Plugin
+This plugin allows users to select multiple items within a sortable at once, and drag them as one item.
+Once placed, the items will unfold into their original order, but all beside each other at the new position.
+[Read More](https://github.com/SortableJS/Sortable/wiki/Dragging-Multiple-Items-in-Sortable)
+
+Demo: https://jsbin.com/wopavom/edit?js,output
+
+
+---
+
+
+### Mounting
+```js
+import { Sortable, MultiDrag } from 'sortablejs';
+
+Sortable.mount(new MultiDrag());
+```
+
+
+---
+
+
+### Options
+
+```js
+new Sortable(el, {
+	multiDrag: true, // Enable the plugin
+	selectedClass: "sortable-selected", // Class name for selected item
+	multiDragKey: null, // Key that must be down for items to be selected
+
+	// Called when an item is selected
+	onSelect: function(/**Event*/evt) {
+		evt.item // The selected item
+	},
+
+	// Called when an item is deselected
+	onDeselect: function(/**Event*/evt) {
+		evt.item // The deselected item
+	}
+});
+```
+
+
+---
+
+
+#### `multiDragKey` option
+The key that must be down for multiple items to be selected. The default is `null`, meaning no key must be down.
+For special keys, such as the <kbd>CTRL</kbd> key, simply specify the option as `'CTRL'` (casing does not matter).
+
+
+---
+
+
+#### `selectedClass` option
+Class name for the selected item(s) if multiDrag is enabled. Defaults to `sortable-selected`.
+
+```css
+.selected {
+  background-color: #f9c7c8;
+  border: solid red 1px;
+}
+```
+
+```js
+Sortable.create(list, {
+  multiDrag: true,
+  selectedClass: "selected"
+});
+```
+
+
+---
+
+
+### Event Properties
+ - items:`HTMLElement[]` — Array of selected items, or empty
+ - clones:`HTMLElement[]` — Array of clones, or empty
+ - oldIndicies:`Index[]` — Array containing information on the old indicies of the selected elements.
+ - newIndicies:`Index[]` — Array containing information on the new indicies of the selected elements.
+
+#### Index Object
+ - element:`HTMLElement` — The element whose index is being given
+ - index:`Number` — The index of the element
+
+#### Note on `newIndicies`
+For any event that is fired during sorting, the index of any selected element that is not the main dragged element is given as `-1`.
+This is because it has either been removed from the DOM, or because it is in a folding animation (folding to the dragged element) and will be removed after this animation is complete.
+
+
+---
+
+
+### Sortable.utils
+* select(el:`HTMLElement`) — select the given multi-drag item
+* deselect(el:`HTMLElement`) — deselect the given multi-drag item

+ 1 - 0
public/assets/libs/Sortable/plugins/MultiDrag/index.js

@@ -0,0 +1 @@
+export { default } from './MultiDrag.js';

+ 79 - 0
public/assets/libs/Sortable/plugins/OnSpill/OnSpill.js

@@ -0,0 +1,79 @@
+import { getChild } from '../../src/utils.js';
+
+
+const drop = function({
+	originalEvent,
+	putSortable,
+	dragEl,
+	activeSortable,
+	dispatchSortableEvent,
+	hideGhostForTarget,
+	unhideGhostForTarget
+}) {
+	if (!originalEvent) return;
+	let toSortable = putSortable || activeSortable;
+	hideGhostForTarget();
+	let touch = originalEvent.changedTouches && originalEvent.changedTouches.length ? originalEvent.changedTouches[0] : originalEvent;
+	let target = document.elementFromPoint(touch.clientX, touch.clientY);
+	unhideGhostForTarget();
+	if (toSortable && !toSortable.el.contains(target)) {
+		dispatchSortableEvent('spill');
+		this.onSpill({ dragEl, putSortable });
+	}
+};
+
+function Revert() {}
+
+Revert.prototype = {
+	startIndex: null,
+	dragStart({ oldDraggableIndex }) {
+		this.startIndex = oldDraggableIndex;
+	},
+	onSpill({ dragEl, putSortable }) {
+		this.sortable.captureAnimationState();
+		if (putSortable) {
+			putSortable.captureAnimationState();
+		}
+		let nextSibling = getChild(this.sortable.el, this.startIndex, this.options);
+
+		if (nextSibling) {
+			this.sortable.el.insertBefore(dragEl, nextSibling);
+		} else {
+			this.sortable.el.appendChild(dragEl);
+		}
+		this.sortable.animateAll();
+		if (putSortable) {
+			putSortable.animateAll();
+		}
+	},
+	drop
+};
+
+Object.assign(Revert, {
+	pluginName: 'revertOnSpill'
+});
+
+
+function Remove() {}
+
+Remove.prototype = {
+	onSpill({ dragEl, putSortable }) {
+		const parentSortable = putSortable || this.sortable;
+		parentSortable.captureAnimationState();
+		dragEl.parentNode && dragEl.parentNode.removeChild(dragEl);
+		parentSortable.animateAll();
+	},
+	drop
+};
+
+Object.assign(Remove, {
+	pluginName: 'removeOnSpill'
+});
+
+
+export default [Remove, Revert];
+
+export {
+	Remove as RemoveOnSpill,
+	Revert as RevertOnSpill
+};

+ 60 - 0
public/assets/libs/Sortable/plugins/OnSpill/README.md

@@ -0,0 +1,60 @@
+# OnSpill Plugins
+This file contains two seperate plugins, RemoveOnSpill and RevertOnSpill. They can be imported individually, or the default export (an array of both plugins) can be passed to `Sortable.mount` as well.
+
+**These plugins are default plugins, and are included in the default UMD and ESM builds of Sortable**
+
+
+---
+
+
+### Mounting
+```js
+import { Sortable, OnSpill } from 'sortablejs/modular/sortable.core.esm';
+
+Sortable.mount(OnSpill);
+```
+
+
+---
+
+
+## RevertOnSpill Plugin
+This plugin, when enabled, will cause the dragged item to be reverted to it's original position if it is spilled (ie. it is dropped outside of a valid Sortable drop target)
+
+
+
+
+### Options
+
+```js
+new Sortable(el, {
+	revertOnSpill: true, // Enable plugin
+	// Called when item is spilled
+	onSpill: function(/**Event*/evt) {
+		evt.item // The spilled item
+	}
+});
+```
+
+
+---
+
+
+## RemoveOnSpill Plugin
+This plugin, when enabled, will cause the dragged item to be removed from the DOM if it is spilled (ie. it is dropped outside of a valid Sortable drop target)
+
+
+---
+
+
+### Options
+
+```js
+new Sortable(el, {
+	removeOnSpill: true, // Enable plugin
+	// Called when item is spilled
+	onSpill: function(/**Event*/evt) {
+		evt.item // The spilled item
+	}
+});
+```

+ 1 - 0
public/assets/libs/Sortable/plugins/OnSpill/index.js

@@ -0,0 +1 @@
+export { default, RemoveOnSpill, RevertOnSpill } from './OnSpill.js';

+ 178 - 0
public/assets/libs/Sortable/plugins/README.md

@@ -0,0 +1,178 @@
+# Creating Sortable Plugins
+Sortable plugins are plugins that can be directly mounted to the Sortable class. They are a powerful way of modifying the default behaviour of Sortable beyond what simply using events alone allows. To mount your plugin to Sortable, it must pass a constructor function to the `Sortable.mount` function. This constructor function will be called (with the `new` keyword in front of it) whenever a Sortable instance with your plugin enabled is initialized. The constructor function will be called with the parameters `sortable` and `el`, which is the HTMLElement that the Sortable is being initialized on. This means that there will be a new instance of your plugin each time it is enabled in a Sortable.
+
+
+## Constructor Parameters
+
+`sortable: Sortable` — The sortable that the plugin is being initialized on
+
+`el: HTMLElement` — The element that the sortable is being initialized on
+
+`options: Object` — The options object that the user has passed into Sortable (not merged with defaults yet)
+
+
+## Static Properties
+The constructor function passed to `Sortable.mount` may contain several static properties and methods. The following static properties may be defined:
+
+`pluginName: String` (Required)
+The name of the option that the user will use in their sortable's options to enable the plugin. Should start with a lower case and be camel-cased. For example: `'multiDrag'`. This is also the property name that the plugin's instance will be under in a sortable instance (ex. `sortableInstance.multiDrag`).
+
+`utils: Object`
+Object containing functions that will be added to the `Sortable.utils` static object on the Sortable class.
+
+`eventOptions(eventName: String): Function`
+A function that is called whenever Sortable fires an event. This function should return an object to be combined with the event object that Sortable will emit. The function will be called in the context of the instance of the plugin on the Sortable that is firing the event (ie. the `this` keyword will be the plugin instance).
+
+`initializeByDefault: Boolean`
+Determines whether or not the plugin will always be initialized on every new Sortable instance. If this option is enabled, it does not mean that by default the plugin will be enabled on the Sortable - this must still be done in the options via the plugin's `pluginName`, or it can be enabled by default if your plugin specifies it's pluginName as a default option that is truthy. Since the plugin will already be initialized on every Sortable instance, it can also be enabled dynamically via `sortableInstance.option('pluginName', true)`.
+It is a good idea to have this option set to `false` if the plugin modifies the behaviour of Sortable in such a way that enabling or disabling the plugin dynamically could cause it to break. Likewise, this option should be disabled if the plugin should only be instantiated on Sortables in which that plugin is enabled.
+This option defaults to `true`.
+
+`optionListeners: Object`
+An object that may contain event listeners that are fired when a specific option is updated.
+These listeners are useful because the user's provided options are not necessarily unchanging once the plugin is initialized, and could be changed dynamically via the `option()` method.
+The listener will be fired in the context of the instance of the plugin that it is being changed in (ie. the `this` keyword will be the instance of your plugin).
+The name of the method should match the name of the option it listens for. The new value of the option will be passed in as an argument, and any returned value will be what the option is stored as. If no value is returned, the option will be stored as the value the user provided.
+
+Example:
+
+```js
+Plugin.name = 'generateTitle';
+Plugin.optionListeners = {
+	// Listen for option 'generateTitle'
+	generateTitle: function(title) {
+		// Store the option in all caps
+		return title.toUpperCase();
+
+		// OR save it to this instance of your plugin as a private field.
+		// This way it can be accessed in events, but will not modify the user's options.
+		this.titleAllCaps = title.toUpperCase();
+	}
+};
+
+``` 
+
+## Plugin Options
+Plugins may have custom default options or may override the defaults of other options. In order to do this, there must be a `defaults` object on the initialized plugin. This can be set in the plugin's prototype, or during the initialization of the plugin (when the `el` is available). For example:
+
+```js
+function myPlugin(sortable, el, options) {
+	this.defaults = {
+		color: el.style.backgroundColor
+	};
+}
+
+Sortable.mount(myPlugin);
+```
+
+
+## Plugin Events
+
+### Context
+The events will be fired in the context of their own parent object (ie. context is not changed), however the plugin instance's Sortable instance is available under `this.sortable`. Likewise, the options are available under `this.options`.
+
+### Event List
+The following table contains details on the events that a plugin may handle in the prototype of the plugin's constructor function.
+
+| Event Name                | Description                                                                                                      | Cancelable? | Cancel Behaviour                                   | Event Type | Custom Event Object Properties                                          |
+|---------------------------|------------------------------------------------------------------------------------------------------------------|-------------|----------------------------------------------------|------------|-------------------------------------------------------------------------|
+| filter                    | Fired when the element is filtered, and dragging is therefore canceled                                           | No          | -                                                  | Normal     | None                                                                    |
+| delayStart                | Fired when the delay starts, even if there is no delay                                                           | Yes         | Cancels sorting                                    | Normal     | None                                                                    |
+| delayEnded                | Fired when the delay ends, even if there is no delay                                                             | Yes         | Cancels sorting                                    | Normal     | None                                                                    |
+| setupClone                | Fired when Sortable clones the dragged element                                                                   | Yes         | Cancels normal clone setup                         | Normal     | None                                                                    |
+| dragStart                 | Fired when the dragging is first started                                                                         | Yes         | Cancels sorting                                    | Normal     | None                                                                    |
+| clone                     | Fired when the clone is inserted into the DOM (if `removeCloneOnHide: false`). Tick after dragStart.             | Yes         | Cancels normal clone insertion & hiding            | Normal     | None                                                                    |
+| dragStarted               | Fired tick after dragStart                                                                                       | No          | -                                                  | Normal     | None                                                                    |
+| dragOver                  | Fired when the user drags over a sortable                                                                        | Yes         | Cancels normal dragover behaviour                  | DragOver   | None                                                                    |
+| dragOverValid             | Fired when the user drags over a sortable that the dragged item can be inserted into                             | Yes         | Cancels normal valid dragover behaviour            | DragOver   | None                                                                    |
+| revert                    | Fired when the dragged item is reverted to it's original position when entering it's `sort:false` root           | Yes         | Cancels normal reverting, but is still completed() | DragOver   | None                                                                    |
+| dragOverCompleted         | Fired when dragOver is completed (ie. bubbling is disabled). To check if inserted, use `inserted` even property. | No          | -                                                  | DragOver   | `insertion: Boolean` — Whether or not the dragged element was inserted  |
+| dragOverAnimationCapture  | Fired right before the animation state is captured in dragOver                                                   | No          | -                                                  | DragOver   | None                                                                    |
+| dragOverAnimationComplete | Fired after the animation is completed after a dragOver insertion                                                | No          | -                                                  | DragOver   | None                                                                    |
+| drop                      | Fired on drop                                                                                                    | Yes         | Cancels normal drop behavior                       | Normal     | None                                                                    |
+| nulling                   | Fired when the plugin should preform cleanups, once all drop events have fired                                   | No          | -                                                  | Normal     | None                                                                    |
+| destroy                   | Fired when Sortable is destroyed                                                                                 | No          | -                                                  | Normal     | None                                                                    |
+
+### Global Events
+Normally, an event will only be fired in a plugin if the plugin is enabled on the Sortable from which the event is being fired. However, it sometimes may be desirable for a plugin to listen in on an event from Sortables in which it is not enabled on. This is possible with global events. For an event to be global, simply add the suffix 'Global' to the event's name (casing matters) (eg. `dragStartGlobal`).
+Please note that your plugin must be initialized on any Sortable from which it expects to recieve events, and that includes global events. In other words, you will want to keep the `initializeByDefault` option as it's default `true` value if your plugin needs to recieve events from Sortables it is not enabled on.
+Please also note that if both normal and global event handlers are set, the global event handler will always be fired before the regular one.
+
+### Event Object
+An object with the following properties is passed as an argument to each plugin event when it is fired.
+
+#### Properties:
+
+`dragEl: HTMLElement` — The element being dragged
+
+`parentEl: HTMLElement` — The element that the dragged element is currently in
+
+`ghostEl: HTMLElement|undefined` — If using fallback, the element dragged under the cursor (undefined until after `dragStarted` plugin event)
+
+`rootEl: HTMLElement` — The element that the dragged element originated from
+
+`nextEl: HTMLElement` — The original next sibling of dragEl
+
+`cloneEl: HTMLElement|undefined` — The clone element (undefined until after `setupClone` plugin event)
+
+`cloneHidden: Boolean` — Whether or not the clone is hidden
+
+`dragStarted: Boolean` — Boolean indicating whether or not the dragStart event has fired
+
+`putSortable: Sortable|undefined` — The element that dragEl is dragged into from it's root, otherwise undefined 
+
+`activeSortable: Sortable` — The active Sortable instance
+
+`originalEvent: Event` — The original HTML event corresponding to the Sortable event
+
+`oldIndex: Number` — The old index of dragEl
+
+`oldDraggableIndex: Number` — The old index of dragEl, only counting draggable elements
+
+`newIndex: Number` — The new index of dragEl
+
+`newDraggableIndex: Number` — The new index of dragEl, only counting draggable elements
+
+
+#### Methods:
+
+`cloneNowHidden()` — Function to be called if the plugin has hidden the clone
+
+`cloneNowShown()` — Function to be called if the plugin has shown the clone
+
+`hideGhostForTarget()` — Hides the fallback ghost element if CSS pointer-events are not available. Call this before using document.elementFromPoint at the mouse position.
+
+`unhideGhostForTarget()` — Unhides the ghost element. To be called after `hideGhostForTarget()`.
+
+`dispatchSortableEvent(eventName: String)` — Function that can be used to emit an event on the current sortable while sorting, with all usual event properties set (eg. indexes, rootEl, cloneEl, originalEvent, etc.).
+
+
+### DragOverEvent Object
+This event is passed to dragover events, and extends the normal event object.
+
+#### Properties:
+
+`isOwner: Boolean` — Whether or not the dragged over sortable currently contains the dragged element
+
+`axis: String` — Direction of the dragged over sortable, `'vertical'` or `'horizontal'`
+
+`revert: Boolean` — Whether or not the dragged element is being reverted to it's original position from another position
+
+`dragRect: DOMRect` — DOMRect of the dragged element
+
+`targetRect: DOMRect` — DOMRect of the target element
+
+`canSort: Boolean` — Whether or not sorting is enabled in the dragged over sortable
+
+`fromSortable: Sortable` — The sortable that the dragged element is coming from
+
+`target: HTMLElement` — The sortable item that is being dragged over
+
+
+#### Methods:
+
+`onMove(target: HTMLElement, after: Boolean): Boolean|Number` — Calls the `onMove` function the user specified in the options
+
+`changed()` — Fires the `onChange` event with event properties preconfigured
+
+`completed(insertion: Boolean)` — Should be called when dragover has "completed", meaning bubbling should be stopped. If `insertion` is `true`, Sortable will treat it as if the dragged element was inserted into the sortable, and hide/show clone, set ghost class, animate, etc.

+ 55 - 0
public/assets/libs/Sortable/plugins/Swap/README.md

@@ -0,0 +1,55 @@
+## Swap Plugin
+This plugin modifies the behaviour of Sortable to allow for items to be swapped with eachother rather than sorted. Once dragging starts, the user can drag over other items and there will be no change in the elements. However, the item that the user drops on will be swapped with the originally dragged item.
+
+Demo: https://jsbin.com/yejehog/edit?html,js,output
+
+
+---
+
+
+### Mounting
+```js
+import { Sortable, Swap } from 'sortablejs/modular/sortable.core.esm';
+
+Sortable.mount(new Swap());
+```
+
+
+---
+
+
+### Options
+
+```js
+new Sortable(el, {
+	swap: true, // Enable swap mode
+	swapClass: "sortable-swap-highlight" // Class name for swap item (if swap mode is enabled)
+});
+```
+
+
+---
+
+
+#### `swapClass` option
+Class name for the item to be swapped with, if swap mode is enabled. Defaults to `sortable-swap-highlight`.
+
+```css
+.highlighted {
+  background-color: #9AB6F1;
+}
+```
+
+```js
+Sortable.create(list, {
+  swap: true,
+  swapClass: "highlighted"
+});
+```
+
+
+---
+
+
+### Event Properties
+ - swapItem:`HTMLElement|undefined` — The element that the dragged element was swapped with

+ 90 - 0
public/assets/libs/Sortable/plugins/Swap/Swap.js

@@ -0,0 +1,90 @@
+import {
+	toggleClass,
+	index
+} from '../../src/utils.js';
+
+let lastSwapEl;
+
+
+function SwapPlugin() {
+	function Swap() {
+		this.defaults = {
+			swapClass: 'sortable-swap-highlight'
+		};
+	}
+
+	Swap.prototype = {
+		dragStart({ dragEl }) {
+			lastSwapEl = dragEl;
+		},
+		dragOverValid({ completed, target, onMove, activeSortable, changed, cancel }) {
+			if (!activeSortable.options.swap) return;
+			let el = this.sortable.el,
+				options = this.options;
+			if (target && target !== el) {
+				let prevSwapEl = lastSwapEl;
+				if (onMove(target) !== false) {
+					toggleClass(target, options.swapClass, true);
+					lastSwapEl = target;
+				} else {
+					lastSwapEl = null;
+				}
+
+				if (prevSwapEl && prevSwapEl !== lastSwapEl) {
+					toggleClass(prevSwapEl, options.swapClass, false);
+				}
+			}
+			changed();
+
+			completed(true);
+			cancel();
+		},
+		drop({ activeSortable, putSortable, dragEl }) {
+			let toSortable = (putSortable || this.sortable);
+			let options = this.options;
+			lastSwapEl && toggleClass(lastSwapEl, options.swapClass, false);
+			if (lastSwapEl && (options.swap || putSortable && putSortable.options.swap)) {
+				if (dragEl !== lastSwapEl) {
+					toSortable.captureAnimationState();
+					if (toSortable !== activeSortable) activeSortable.captureAnimationState();
+					swapNodes(dragEl, lastSwapEl);
+
+					toSortable.animateAll();
+					if (toSortable !== activeSortable) activeSortable.animateAll();
+				}
+			}
+		},
+		nulling() {
+			lastSwapEl = null;
+		}
+	};
+
+	return Object.assign(Swap, {
+		pluginName: 'swap',
+		eventProperties() {
+			return {
+				swapItem: lastSwapEl
+			};
+		}
+	});
+}
+
+
+function swapNodes(n1, n2) {
+	let p1 = n1.parentNode,
+		p2 = n2.parentNode,
+		i1, i2;
+
+	if (!p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1)) return;
+
+	i1 = index(n1);
+	i2 = index(n2);
+
+	if (p1.isEqualNode(p2) && i1 < i2) {
+		i2++;
+	}
+	p1.insertBefore(n2, p1.children[i1]);
+	p2.insertBefore(n1, p2.children[i2]);
+}
+
+export default SwapPlugin;

+ 1 - 0
public/assets/libs/Sortable/plugins/Swap/index.js

@@ -0,0 +1 @@
+export { default } from './Swap.js';

+ 8 - 0
public/assets/libs/Sortable/scripts/banner.js

@@ -0,0 +1,8 @@
+import { version } from '../package.json';
+
+export default `/**!
+ * Sortable ${ version }
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @author	owenm    <owen23355@gmail.com>
+ * @license MIT
+ */`;

+ 17 - 0
public/assets/libs/Sortable/scripts/build.js

@@ -0,0 +1,17 @@
+import babel from 'rollup-plugin-babel';
+import json from 'rollup-plugin-json';
+import resolve from 'rollup-plugin-node-resolve';
+import banner from './banner.js';
+
+
+export default {
+	output: {
+		banner,
+		name: 'Sortable'
+	},
+	plugins: [
+		json(),
+		babel(),
+		resolve()
+    ]
+};

+ 28 - 0
public/assets/libs/Sortable/scripts/esm-build.js

@@ -0,0 +1,28 @@
+import build from './build.js';
+
+export default ([
+	{
+		input: 'entry/entry-core.js',
+		output: Object.assign({}, build.output, {
+			file: 'modular/sortable.core.esm.js',
+			format: 'esm'
+		})
+	},
+	{
+		input: 'entry/entry-defaults.js',
+		output: Object.assign({}, build.output, {
+			file: 'modular/sortable.esm.js',
+			format: 'esm'
+		})
+	},
+	{
+		input: 'entry/entry-complete.js',
+		output: Object.assign({}, build.output, {
+			file: 'modular/sortable.complete.esm.js',
+			format: 'esm'
+		})
+	}
+]).map(config => {
+	let buildCopy = { ...build };
+	return Object.assign(buildCopy, config);
+});

+ 11 - 0
public/assets/libs/Sortable/scripts/minify.js

@@ -0,0 +1,11 @@
+const UglifyJS = require('uglify-js'),
+	fs = require('fs'),
+ 	package = require('../package.json');
+
+const banner = `/*! Sortable ${ package.version } - ${ package.license } | ${ package.repository.url } */\n`;
+
+fs.writeFileSync(
+	`./Sortable.min.js`,
+	banner + UglifyJS.minify(fs.readFileSync(`./Sortable.js`, 'utf8')).code,
+	'utf8'
+);

+ 30 - 0
public/assets/libs/Sortable/scripts/test-compat.js

@@ -0,0 +1,30 @@
+const createTestCafe = require('testcafe');
+// Testcafe cannot test on IE < 11
+// Testcafe testing on Chrome Android is currently broken (https://github.com/DevExpress/testcafe/issues/3948)
+const browsers = [
+	'saucelabs:Internet Explorer@11.285:Windows 10',
+	'saucelabs:MicrosoftEdge@16.16299:Windows 10',
+	'saucelabs:iPhone XS Simulator@12.2',
+	'saucelabs:Safari@12.0:macOS 10.14',
+	'chrome:headless',
+	'firefox:headless'
+];
+
+let testcafe;
+let runner;
+let failedCount;
+
+createTestCafe(null, 8000, 8001).then((tc) => {
+	testcafe = tc;
+	runner = tc.createRunner();
+	return runner
+		.src('./tests/Sortable.compat.test.js')
+		.browsers(browsers)
+		.run();
+}).then((actualFailedCount) => {
+	// https://testcafe-discuss.devexpress.com/t/why-circleci-marked-build-as-green-even-if-this-build-contain-failed-test/726/2
+	failedCount = actualFailedCount;
+    return testcafe.close();
+}).then(() => process.exit(failedCount));
+
+

+ 21 - 0
public/assets/libs/Sortable/scripts/test.js

@@ -0,0 +1,21 @@
+const createTestCafe = require('testcafe');
+
+let testcafe;
+let runner;
+let failedCount;
+
+
+createTestCafe().then((tc) => {
+	testcafe = tc;
+	runner = tc.createRunner();
+	return runner
+		.src('./tests/Sortable.test.js')
+		.browsers('chrome:headless')
+		.concurrency(3)
+		.run();
+}).then((actualFailedCount) => {
+	failedCount = actualFailedCount;
+	console.log('FAILED COUNT', actualFailedCount)
+    return testcafe.close();
+}).then(() => process.exit(failedCount));
+

+ 15 - 0
public/assets/libs/Sortable/scripts/umd-build.js

@@ -0,0 +1,15 @@
+import build from './build.js';
+
+
+export default ([
+	{
+		input: 'entry/entry-complete.js',
+		output: Object.assign({}, build.output, {
+			file: './Sortable.js',
+			format: 'umd'
+		})
+	}
+]).map(config => {
+	let buildCopy = { ...build };
+	return Object.assign(buildCopy, config);
+});

+ 175 - 0
public/assets/libs/Sortable/src/Animation.js

@@ -0,0 +1,175 @@
+import { getRect, css, matrix, isRectEqual, indexOfObject } from './utils.js';
+import Sortable from './Sortable.js';
+
+export default function AnimationStateManager() {
+	let animationStates = [],
+		animationCallbackId;
+
+	return {
+		captureAnimationState() {
+			animationStates = [];
+			if (!this.options.animation) return;
+			let children = [].slice.call(this.el.children);
+
+			children.forEach(child => {
+				if (css(child, 'display') === 'none' || child === Sortable.ghost) return;
+				animationStates.push({
+					target: child,
+					rect: getRect(child)
+				});
+				let fromRect = { ...animationStates[animationStates.length - 1].rect };
+
+				// If animating: compensate for current animation
+				if (child.thisAnimationDuration) {
+					let childMatrix = matrix(child, true);
+					if (childMatrix) {
+						fromRect.top -= childMatrix.f;
+						fromRect.left -= childMatrix.e;
+					}
+				}
+
+				child.fromRect = fromRect;
+			});
+		},
+
+		addAnimationState(state) {
+			animationStates.push(state);
+		},
+
+		removeAnimationState(target) {
+			animationStates.splice(indexOfObject(animationStates, { target }), 1);
+		},
+
+		animateAll(callback) {
+			if (!this.options.animation) {
+				clearTimeout(animationCallbackId);
+				if (typeof(callback) === 'function') callback();
+				return;
+			}
+
+			let animating = false,
+				animationTime = 0;
+
+			animationStates.forEach((state) => {
+				let time = 0,
+					animatingThis = false,
+					target = state.target,
+					fromRect = target.fromRect,
+					toRect = getRect(target),
+					prevFromRect = target.prevFromRect,
+					prevToRect = target.prevToRect,
+					animatingRect = state.rect,
+					targetMatrix = matrix(target, true);
+
+
+				if (targetMatrix) {
+					// Compensate for current animation
+					toRect.top -= targetMatrix.f;
+					toRect.left -= targetMatrix.e;
+				}
+
+				target.toRect = toRect;
+
+				if (target.thisAnimationDuration) {
+					// Could also check if animatingRect is between fromRect and toRect
+					if (
+						isRectEqual(prevFromRect, toRect) &&
+						!isRectEqual(fromRect, toRect) &&
+						// Make sure animatingRect is on line between toRect & fromRect
+						(animatingRect.top - toRect.top) /
+						(animatingRect.left - toRect.left) ===
+						(fromRect.top - toRect.top) /
+						(fromRect.left - toRect.left)
+					) {
+						// If returning to same place as started from animation and on same axis
+						time = calculateRealTime(animatingRect, prevFromRect, prevToRect, this.options);
+					}
+				}
+
+				// if fromRect != toRect: animate
+				if (!isRectEqual(toRect, fromRect)) {
+					target.prevFromRect = fromRect;
+					target.prevToRect = toRect;
+
+					if (!time) {
+						time = this.options.animation;
+					}
+					this.animate(
+						target,
+						animatingRect,
+						toRect,
+						time
+					);
+				}
+
+				if (time) {
+					animating = true;
+					animationTime = Math.max(animationTime, time);
+					clearTimeout(target.animationResetTimer);
+					target.animationResetTimer = setTimeout(function() {
+						target.animationTime = 0;
+						target.prevFromRect = null;
+						target.fromRect = null;
+						target.prevToRect = null;
+						target.thisAnimationDuration = null;
+					}, time);
+					target.thisAnimationDuration = time;
+				}
+			});
+
+
+			clearTimeout(animationCallbackId);
+			if (!animating) {
+				if (typeof(callback) === 'function') callback();
+			} else {
+				animationCallbackId = setTimeout(function() {
+					if (typeof(callback) === 'function') callback();
+				}, animationTime);
+			}
+			animationStates = [];
+		},
+
+		animate(target, currentRect, toRect, duration) {
+			if (duration) {
+				css(target, 'transition', '');
+				css(target, 'transform', '');
+				let elMatrix = matrix(this.el),
+					scaleX = elMatrix && elMatrix.a,
+					scaleY = elMatrix && elMatrix.d,
+					translateX = (currentRect.left - toRect.left) / (scaleX || 1),
+					translateY = (currentRect.top - toRect.top) / (scaleY || 1);
+
+				target.animatingX = !!translateX;
+				target.animatingY = !!translateY;
+
+				css(target, 'transform', 'translate3d(' + translateX + 'px,' + translateY + 'px,0)');
+
+				repaint(target); // repaint
+
+				css(target, 'transition', 'transform ' + duration + 'ms' + (this.options.easing ? ' ' + this.options.easing : ''));
+				css(target, 'transform', 'translate3d(0,0,0)');
+				(typeof target.animated === 'number') && clearTimeout(target.animated);
+				target.animated = setTimeout(function () {
+					css(target, 'transition', '');
+					css(target, 'transform', '');
+					target.animated = false;
+
+					target.animatingX = false;
+					target.animatingY = false;
+				}, duration);
+			}
+		}
+	};
+}
+
+function repaint(target) {
+	return target.offsetWidth;
+}
+
+
+function calculateRealTime(animatingRect, fromRect, toRect, options) {
+	return (
+		Math.sqrt(Math.pow(fromRect.top - animatingRect.top, 2) + Math.pow(fromRect.left - animatingRect.left, 2)) /
+		Math.sqrt(Math.pow(fromRect.top - toRect.top, 2) + Math.pow(fromRect.left - toRect.left, 2))
+	) * options.animation;
+}

+ 12 - 0
public/assets/libs/Sortable/src/BrowserInfo.js

@@ -0,0 +1,12 @@
+function userAgent(pattern) {
+	if (typeof window !== 'undefined' && window.navigator) {
+		return !!/*@__PURE__*/navigator.userAgent.match(pattern);
+	}
+}
+
+export const IE11OrLess = userAgent(/(?:Trident.*rv[ :]?11\.|msie|iemobile|Windows Phone)/i);
+export const Edge = userAgent(/Edge/i);
+export const FireFox = userAgent(/firefox/i);
+export const Safari = userAgent(/safari/i) && !userAgent(/chrome/i) && !userAgent(/android/i);
+export const IOS = userAgent(/iP(ad|od|hone)/i);
+export const ChromeForAndroid = userAgent(/chrome/i) && userAgent(/android/i);

+ 57 - 0
public/assets/libs/Sortable/src/EventDispatcher.js

@@ -0,0 +1,57 @@
+import { IE11OrLess, Edge } from './BrowserInfo.js';
+import { expando } from './utils.js';
+import PluginManager from './PluginManager.js';
+
+export default function dispatchEvent(
+	{
+		sortable, rootEl, name,
+		targetEl, cloneEl, toEl, fromEl,
+		oldIndex, newIndex,
+		oldDraggableIndex, newDraggableIndex,
+		originalEvent, putSortable, extraEventProperties
+	}
+) {
+	sortable = (sortable || (rootEl && rootEl[expando]));
+	if (!sortable) return;
+
+	let evt,
+		options = sortable.options,
+		onName = 'on' + name.charAt(0).toUpperCase() + name.substr(1);
+	// Support for new CustomEvent feature
+	if (window.CustomEvent && !IE11OrLess && !Edge) {
+		evt = new CustomEvent(name, {
+			bubbles: true,
+			cancelable: true
+		});
+	} else {
+		evt = document.createEvent('Event');
+		evt.initEvent(name, true, true);
+	}
+
+	evt.to = toEl || rootEl;
+	evt.from = fromEl || rootEl;
+	evt.item = targetEl || rootEl;
+	evt.clone = cloneEl;
+
+	evt.oldIndex = oldIndex;
+	evt.newIndex = newIndex;
+
+	evt.oldDraggableIndex = oldDraggableIndex;
+	evt.newDraggableIndex = newDraggableIndex;
+
+	evt.originalEvent = originalEvent;
+	evt.pullMode = putSortable ? putSortable.lastPutMode : undefined;
+
+	let allEventProperties = { ...extraEventProperties, ...PluginManager.getEventProperties(name, sortable) };
+	for (let option in allEventProperties) {
+		evt[option] = allEventProperties[option];
+	}
+
+	if (rootEl) {
+		rootEl.dispatchEvent(evt);
+	}
+
+	if (options[onName]) {
+		options[onName].call(sortable, evt);
+	}
+}

+ 87 - 0
public/assets/libs/Sortable/src/PluginManager.js

@@ -0,0 +1,87 @@
+let plugins = [];
+
+const defaults = {
+	initializeByDefault: true
+};
+
+export default {
+	mount(plugin) {
+		// Set default static properties
+		for (let option in defaults) {
+			if (defaults.hasOwnProperty(option) && !(option in plugin)) {
+				plugin[option] = defaults[option];
+			}
+		}
+		plugins.push(plugin);
+	},
+	pluginEvent(eventName, sortable, evt) {
+		this.eventCanceled = false;
+		evt.cancel = () => {
+			this.eventCanceled = true;
+		};
+		const eventNameGlobal = eventName + 'Global';
+		plugins.forEach(plugin => {
+			if (!sortable[plugin.pluginName]) return;
+			// Fire global events if it exists in this sortable
+			if (
+				sortable[plugin.pluginName][eventNameGlobal]
+			) {
+				sortable[plugin.pluginName][eventNameGlobal]({ sortable, ...evt });
+			}
+
+			// Only fire plugin event if plugin is enabled in this sortable,
+			// and plugin has event defined
+			if (
+				sortable.options[plugin.pluginName] &&
+				sortable[plugin.pluginName][eventName]
+			) {
+				sortable[plugin.pluginName][eventName]({ sortable, ...evt });
+			}
+		});
+	},
+	initializePlugins(sortable, el, defaults, options) {
+		plugins.forEach(plugin => {
+			const pluginName = plugin.pluginName;
+			if (!sortable.options[pluginName] && !plugin.initializeByDefault) return;
+
+			let initialized = new plugin(sortable, el, sortable.options);
+			initialized.sortable = sortable;
+			initialized.options = sortable.options;
+			sortable[pluginName] = initialized;
+
+			// Add default options from plugin
+			Object.assign(defaults, initialized.defaults);
+		});
+
+		for (let option in sortable.options) {
+			if (!sortable.options.hasOwnProperty(option)) continue;
+			let modified = this.modifyOption(sortable, option, sortable.options[option]);
+			if (typeof(modified) !== 'undefined') {
+				sortable.options[option] = modified;
+			}
+		}
+	},
+	getEventProperties(name, sortable) {
+		let eventProperties = {};
+		plugins.forEach(plugin => {
+			if (typeof(plugin.eventProperties) !== 'function') return;
+			Object.assign(eventProperties, plugin.eventProperties.call(sortable[plugin.pluginName], name));
+		});
+
+		return eventProperties;
+	},
+	modifyOption(sortable, name, value) {
+		let modifiedValue;
+		plugins.forEach(plugin => {
+			// Plugin must exist on the Sortable
+			if (!sortable[plugin.pluginName]) return;
+
+			// If static option listener exists for this option, call in the context of the Sortable's instance of this plugin
+			if (plugin.optionListeners && typeof(plugin.optionListeners[name]) === 'function') {
+				modifiedValue = plugin.optionListeners[name].call(sortable[plugin.pluginName], value);
+			}
+		});
+
+		return modifiedValue;
+	}
+};

+ 1966 - 0
public/assets/libs/Sortable/src/Sortable.js

@@ -0,0 +1,1966 @@
+/**!
+ * Sortable
+ * @author	RubaXa   <trash@rubaxa.org>
+ * @author	owenm    <owen23355@gmail.com>
+ * @license MIT
+ */
+
+import { version } from '../package.json';
+
+import { IE11OrLess, Edge, FireFox, Safari, IOS, ChromeForAndroid } from './BrowserInfo.js';
+
+import AnimationStateManager from './Animation.js';
+
+import PluginManager from './PluginManager.js';
+
+import dispatchEvent from './EventDispatcher.js';
+
+import {
+	on,
+	off,
+	closest,
+	toggleClass,
+	css,
+	matrix,
+	find,
+	getWindowScrollingElement,
+	getRect,
+	isScrolledPast,
+	getChild,
+	lastChild,
+	index,
+	getRelativeScrollOffset,
+	extend,
+	throttle,
+	scrollBy,
+	clone,
+	expando
+} from './utils.js';
+
+
+let pluginEvent = function(eventName, sortable, { evt: originalEvent, ...data } = {}) {
+	PluginManager.pluginEvent.bind(Sortable)(eventName, sortable, {
+		dragEl,
+		parentEl,
+		ghostEl,
+		rootEl,
+		nextEl,
+		lastDownEl,
+		cloneEl,
+		cloneHidden,
+		dragStarted: moved,
+		putSortable,
+		activeSortable: Sortable.active,
+		originalEvent,
+
+		oldIndex,
+		oldDraggableIndex,
+		newIndex,
+		newDraggableIndex,
+
+		hideGhostForTarget: _hideGhostForTarget,
+		unhideGhostForTarget: _unhideGhostForTarget,
+
+
+		cloneNowHidden() {
+			cloneHidden = true;
+		},
+		cloneNowShown() {
+			cloneHidden = false;
+		},
+
+		dispatchSortableEvent(name) {
+			_dispatchEvent({ sortable, name, originalEvent });
+		},
+
+		...data
+	});
+};
+
+function _dispatchEvent(info) {
+	dispatchEvent({
+		putSortable,
+		cloneEl,
+		targetEl: dragEl,
+		rootEl,
+		oldIndex,
+		oldDraggableIndex,
+		newIndex,
+		newDraggableIndex,
+		...info
+	});
+}
+
+
+let dragEl,
+	parentEl,
+	ghostEl,
+	rootEl,
+	nextEl,
+	lastDownEl,
+
+	cloneEl,
+	cloneHidden,
+
+	oldIndex,
+	newIndex,
+	oldDraggableIndex,
+	newDraggableIndex,
+
+	activeGroup,
+	putSortable,
+
+	awaitingDragStarted = false,
+	ignoreNextClick = false,
+	sortables = [],
+
+	tapEvt,
+	touchEvt,
+	lastDx,
+	lastDy,
+	tapDistanceLeft,
+	tapDistanceTop,
+
+	moved,
+
+	lastTarget,
+	lastDirection,
+	pastFirstInvertThresh = false,
+	isCircumstantialInvert = false,
+
+	targetMoveDistance,
+
+	// For positioning ghost absolutely
+	ghostRelativeParent,
+	ghostRelativeParentInitialScroll = [], // (left, top)
+
+	_silent = false,
+	savedInputChecked = [];
+
+	/** @const */
+	const documentExists = typeof document !== 'undefined',
+
+	PositionGhostAbsolutely = IOS,
+
+	CSSFloatProperty = Edge || IE11OrLess ? 'cssFloat' : 'float',
+
+	// This will not pass for IE9, because IE9 DnD only works on anchors
+	supportDraggable = documentExists && !ChromeForAndroid && !IOS && ('draggable' in document.createElement('div')),
+
+	supportCssPointerEvents = (function() {
+		if (!documentExists) return;
+		// false when <= IE11
+		if (IE11OrLess) {
+			return false;
+		}
+		let el = document.createElement('x');
+		el.style.cssText = 'pointer-events:auto';
+		return el.style.pointerEvents === 'auto';
+	})(),
+
+	_detectDirection = function(el, options) {
+		let elCSS = css(el),
+			elWidth = parseInt(elCSS.width)
+				- parseInt(elCSS.paddingLeft)
+				- parseInt(elCSS.paddingRight)
+				- parseInt(elCSS.borderLeftWidth)
+				- parseInt(elCSS.borderRightWidth),
+			child1 = getChild(el, 0, options),
+			child2 = getChild(el, 1, options),
+			firstChildCSS = child1 && css(child1),
+			secondChildCSS = child2 && css(child2),
+			firstChildWidth = firstChildCSS && parseInt(firstChildCSS.marginLeft) + parseInt(firstChildCSS.marginRight) + getRect(child1).width,
+			secondChildWidth = secondChildCSS && parseInt(secondChildCSS.marginLeft) + parseInt(secondChildCSS.marginRight) + getRect(child2).width;
+
+		if (elCSS.display === 'flex') {
+			return elCSS.flexDirection === 'column' || elCSS.flexDirection === 'column-reverse'
+			? 'vertical' : 'horizontal';
+		}
+
+		if (elCSS.display === 'grid') {
+			return elCSS.gridTemplateColumns.split(' ').length <= 1 ? 'vertical' : 'horizontal';
+		}
+
+		if (child1 && firstChildCSS.float && firstChildCSS.float !== 'none') {
+			let touchingSideChild2 = firstChildCSS.float === 'left' ? 'left' : 'right';
+
+			return child2 && (secondChildCSS.clear === 'both' || secondChildCSS.clear === touchingSideChild2) ?
+				'vertical' : 'horizontal';
+		}
+
+		return (child1 &&
+			(
+				firstChildCSS.display === 'block' ||
+				firstChildCSS.display === 'flex' ||
+				firstChildCSS.display === 'table' ||
+				firstChildCSS.display === 'grid' ||
+				firstChildWidth >= elWidth &&
+				elCSS[CSSFloatProperty] === 'none' ||
+				child2 &&
+				elCSS[CSSFloatProperty] === 'none' &&
+				firstChildWidth + secondChildWidth > elWidth
+			) ?
+			'vertical' : 'horizontal'
+		);
+	},
+
+	_dragElInRowColumn = function(dragRect, targetRect, vertical) {
+		let dragElS1Opp = vertical ? dragRect.left : dragRect.top,
+			dragElS2Opp = vertical ? dragRect.right : dragRect.bottom,
+			dragElOppLength = vertical ? dragRect.width : dragRect.height,
+			targetS1Opp = vertical ? targetRect.left : targetRect.top,
+			targetS2Opp = vertical ? targetRect.right : targetRect.bottom,
+			targetOppLength = vertical ? targetRect.width : targetRect.height;
+
+		return (
+			dragElS1Opp === targetS1Opp ||
+			dragElS2Opp === targetS2Opp ||
+			(dragElS1Opp + dragElOppLength / 2) === (targetS1Opp + targetOppLength / 2)
+		);
+	},
+
+	/**
+	 * Detects first nearest empty sortable to X and Y position using emptyInsertThreshold.
+	 * @param  {Number} x      X position
+	 * @param  {Number} y      Y position
+	 * @return {HTMLElement}   Element of the first found nearest Sortable
+	 */
+	_detectNearestEmptySortable = function(x, y) {
+		let ret;
+		sortables.some((sortable) => {
+			if (lastChild(sortable)) return;
+
+			let rect = getRect(sortable),
+				threshold = sortable[expando].options.emptyInsertThreshold,
+				insideHorizontally = x >= (rect.left - threshold) && x <= (rect.right + threshold),
+				insideVertically = y >= (rect.top - threshold) && y <= (rect.bottom + threshold);
+
+			if (threshold && insideHorizontally && insideVertically) {
+				return (ret = sortable);
+			}
+		});
+		return ret;
+	},
+
+	_prepareGroup = function (options) {
+		function toFn(value, pull) {
+			return function(to, from, dragEl, evt) {
+				let sameGroup = to.options.group.name &&
+								from.options.group.name &&
+								to.options.group.name === from.options.group.name;
+
+				if (value == null && (pull || sameGroup)) {
+					// Default pull value
+					// Default pull and put value if same group
+					return true;
+				} else if (value == null || value === false) {
+					return false;
+				} else if (pull && value === 'clone') {
+					return value;
+				} else if (typeof value === 'function') {
+					return toFn(value(to, from, dragEl, evt), pull)(to, from, dragEl, evt);
+				} else {
+					let otherGroup = (pull ? to : from).options.group.name;
+
+					return (value === true ||
+					(typeof value === 'string' && value === otherGroup) ||
+					(value.join && value.indexOf(otherGroup) > -1));
+				}
+			};
+		}
+
+		let group = {};
+		let originalGroup = options.group;
+
+		if (!originalGroup || typeof originalGroup != 'object') {
+			originalGroup = {name: originalGroup};
+		}
+
+		group.name = originalGroup.name;
+		group.checkPull = toFn(originalGroup.pull, true);
+		group.checkPut = toFn(originalGroup.put);
+		group.revertClone = originalGroup.revertClone;
+
+		options.group = group;
+	},
+
+	_hideGhostForTarget = function() {
+		if (!supportCssPointerEvents && ghostEl) {
+			css(ghostEl, 'display', 'none');
+		}
+	},
+
+	_unhideGhostForTarget = function() {
+		if (!supportCssPointerEvents && ghostEl) {
+			css(ghostEl, 'display', '');
+		}
+	};
+
+
+// #1184 fix - Prevent click event on fallback if dragged but item not changed position
+if (documentExists) {
+	document.addEventListener('click', function(evt) {
+		if (ignoreNextClick) {
+			evt.preventDefault();
+			evt.stopPropagation && evt.stopPropagation();
+			evt.stopImmediatePropagation && evt.stopImmediatePropagation();
+			ignoreNextClick = false;
+			return false;
+		}
+	}, true);
+}
+
+let nearestEmptyInsertDetectEvent = function(evt) {
+	if (dragEl) {
+		evt = evt.touches ? evt.touches[0] : evt;
+		let nearest = _detectNearestEmptySortable(evt.clientX, evt.clientY);
+
+		if (nearest) {
+			// Create imitation event
+			let event = {};
+			for (let i in evt) {
+				if (evt.hasOwnProperty(i)) {
+					event[i] = evt[i];
+				}
+			}
+			event.target = event.rootEl = nearest;
+			event.preventDefault = void 0;
+			event.stopPropagation = void 0;
+			nearest[expando]._onDragOver(event);
+		}
+	}
+};
+
+
+let _checkOutsideTargetEl = function(evt) {
+	if (dragEl) {
+		dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
+	}
+};
+
+
+/**
+ * @class  Sortable
+ * @param  {HTMLElement}  el
+ * @param  {Object}       [options]
+ */
+function Sortable(el, options) {
+	if (!(el && el.nodeType && el.nodeType === 1)) {
+		throw `Sortable: \`el\` must be an HTMLElement, not ${ {}.toString.call(el) }`;
+	}
+
+	this.el = el; // root element
+	this.options = options = Object.assign({}, options);
+
+
+	// Export instance
+	el[expando] = this;
+
+	let defaults = {
+		group: null,
+		sort: true,
+		disabled: false,
+		store: null,
+		handle: null,
+		draggable: /^[uo]l$/i.test(el.nodeName) ? '>li' : '>*',
+		swapThreshold: 1, // percentage; 0 <= x <= 1
+		invertSwap: false, // invert always
+		invertedSwapThreshold: null, // will be set to same as swapThreshold if default
+		removeCloneOnHide: true,
+		direction: function() {
+			return _detectDirection(el, this.options);
+		},
+		ghostClass: 'sortable-ghost',
+		chosenClass: 'sortable-chosen',
+		dragClass: 'sortable-drag',
+		ignore: 'a, img',
+		filter: null,
+		preventOnFilter: true,
+		animation: 0,
+		easing: null,
+		setData: function (dataTransfer, dragEl) {
+			dataTransfer.setData('Text', dragEl.textContent);
+		},
+		dropBubble: false,
+		dragoverBubble: false,
+		dataIdAttr: 'data-id',
+		delay: 0,
+		delayOnTouchOnly: false,
+		touchStartThreshold: (Number.parseInt ? Number : window).parseInt(window.devicePixelRatio, 10) || 1,
+		forceFallback: false,
+		fallbackClass: 'sortable-fallback',
+		fallbackOnBody: false,
+		fallbackTolerance: 0,
+		fallbackOffset: {x: 0, y: 0},
+		supportPointer: Sortable.supportPointer !== false && ('PointerEvent' in window),
+		emptyInsertThreshold: 5
+	};
+
+	PluginManager.initializePlugins(this, el, defaults);
+
+	// Set default options
+	for (let name in defaults) {
+		!(name in options) && (options[name] = defaults[name]);
+	}
+
+	_prepareGroup(options);
+
+	// Bind all private methods
+	for (let fn in this) {
+		if (fn.charAt(0) === '_' && typeof this[fn] === 'function') {
+			this[fn] = this[fn].bind(this);
+		}
+	}
+
+	// Setup drag mode
+	this.nativeDraggable = options.forceFallback ? false : supportDraggable;
+
+	if (this.nativeDraggable) {
+		// Touch start threshold cannot be greater than the native dragstart threshold
+		this.options.touchStartThreshold = 1;
+	}
+
+	// Bind events
+	if (options.supportPointer) {
+		on(el, 'pointerdown', this._onTapStart);
+	} else {
+		on(el, 'mousedown', this._onTapStart);
+		on(el, 'touchstart', this._onTapStart);
+	}
+
+	if (this.nativeDraggable) {
+		on(el, 'dragover', this);
+		on(el, 'dragenter', this);
+	}
+
+	sortables.push(this.el);
+
+	// Restore sorting
+	options.store && options.store.get && this.sort(options.store.get(this) || []);
+
+	// Add animation state manager
+	Object.assign(this, AnimationStateManager());
+}
+
+Sortable.prototype = /** @lends Sortable.prototype */ {
+	constructor: Sortable,
+
+	_isOutsideThisEl: function(target) {
+		if (!this.el.contains(target) && target !== this.el) {
+			lastTarget = null;
+		}
+	},
+
+	_getDirection: function(evt, target) {
+		return (typeof this.options.direction === 'function') ? this.options.direction.call(this, evt, target, dragEl) : this.options.direction;
+	},
+
+	_onTapStart: function (/** Event|TouchEvent */evt) {
+		if (!evt.cancelable) return;
+		let _this = this,
+			el = this.el,
+			options = this.options,
+			preventOnFilter = options.preventOnFilter,
+			type = evt.type,
+			touch = (evt.touches && evt.touches[0]) || (evt.pointerType && evt.pointerType === 'touch' && evt),
+			target = (touch || evt).target,
+			originalTarget = evt.target.shadowRoot && ((evt.path && evt.path[0]) || (evt.composedPath && evt.composedPath()[0])) || target,
+			filter = options.filter;
+
+		_saveInputCheckedState(el);
+
+
+		// Don't trigger start event when an element is been dragged, otherwise the evt.oldindex always wrong when set option.group.
+		if (dragEl) {
+			return;
+		}
+
+		if (/mousedown|pointerdown/.test(type) && evt.button !== 0 || options.disabled) {
+			return; // only left button and enabled
+		}
+
+		// cancel dnd if original target is content editable
+		if (originalTarget.isContentEditable) {
+			return;
+		}
+
+		target = closest(target, options.draggable, el, false);
+
+
+		if (target && target.animated) {
+			return;
+		}
+
+		if (lastDownEl === target) {
+			// Ignoring duplicate `down`
+			return;
+		}
+
+		// Get the index of the dragged element within its parent
+		oldIndex = index(target);
+		oldDraggableIndex = index(target, options.draggable);
+
+		// Check filter
+		if (typeof filter === 'function') {
+			if (filter.call(this, evt, target, this)) {
+				_dispatchEvent({
+					sortable: _this,
+					rootEl: originalTarget,
+					name: 'filter',
+					targetEl: target,
+					toEl: el,
+					fromEl: el
+				});
+				pluginEvent('filter', _this, { evt });
+				preventOnFilter && evt.cancelable && evt.preventDefault();
+				return; // cancel dnd
+			}
+		}
+		else if (filter) {
+			filter = filter.split(',').some(function (criteria) {
+				criteria = closest(originalTarget, criteria.trim(), el, false);
+
+				if (criteria) {
+					_dispatchEvent({
+						sortable: _this,
+						rootEl: criteria,
+						name: 'filter',
+						targetEl: target,
+						fromEl: el,
+						toEl: el
+					});
+					pluginEvent('filter', _this, { evt });
+					return true;
+				}
+			});
+
+			if (filter) {
+				preventOnFilter && evt.cancelable && evt.preventDefault();
+				return; // cancel dnd
+			}
+		}
+
+		if (options.handle && !closest(originalTarget, options.handle, el, false)) {
+			return;
+		}
+
+		// Prepare `dragstart`
+		this._prepareDragStart(evt, touch, target);
+	},
+
+	_prepareDragStart: function (/** Event */evt, /** Touch */touch, /** HTMLElement */target) {
+		let _this = this,
+			el = _this.el,
+			options = _this.options,
+			ownerDocument = el.ownerDocument,
+			dragStartFn;
+
+		if (target && !dragEl && (target.parentNode === el)) {
+			let dragRect = getRect(target);
+			rootEl = el;
+			dragEl = target;
+			parentEl = dragEl.parentNode;
+			nextEl = dragEl.nextSibling;
+			lastDownEl = target;
+			activeGroup = options.group;
+
+			Sortable.dragged = dragEl;
+
+			tapEvt = {
+				target: dragEl,
+				clientX: (touch || evt).clientX,
+				clientY: (touch || evt).clientY
+			};
+
+			tapDistanceLeft = tapEvt.clientX - dragRect.left;
+			tapDistanceTop = tapEvt.clientY - dragRect.top;
+
+			this._lastX = (touch || evt).clientX;
+			this._lastY = (touch || evt).clientY;
+
+			dragEl.style['will-change'] = 'all';
+
+			dragStartFn = function () {
+				pluginEvent('delayEnded', _this, { evt });
+				if (Sortable.eventCanceled) {
+					_this._onDrop();
+					return;
+				}
+				// Delayed drag has been triggered
+				// we can re-enable the events: touchmove/mousemove
+				_this._disableDelayedDragEvents();
+
+				if (!FireFox && _this.nativeDraggable) {
+					dragEl.draggable = true;
+				}
+
+				// Bind the events: dragstart/dragend
+				_this._triggerDragStart(evt, touch);
+
+				// Drag start event
+				_dispatchEvent({
+					sortable: _this,
+					name: 'choose',
+					originalEvent: evt
+				});
+
+				// Chosen item
+				toggleClass(dragEl, options.chosenClass, true);
+			};
+
+			// Disable "draggable"
+			options.ignore.split(',').forEach(function (criteria) {
+				find(dragEl, criteria.trim(), _disableDraggable);
+			});
+
+			on(ownerDocument, 'dragover', nearestEmptyInsertDetectEvent);
+			on(ownerDocument, 'mousemove', nearestEmptyInsertDetectEvent);
+			on(ownerDocument, 'touchmove', nearestEmptyInsertDetectEvent);
+
+			on(ownerDocument, 'mouseup', _this._onDrop);
+			on(ownerDocument, 'touchend', _this._onDrop);
+			on(ownerDocument, 'touchcancel', _this._onDrop);
+
+			// Make dragEl draggable (must be before delay for FireFox)
+			if (FireFox && this.nativeDraggable) {
+				this.options.touchStartThreshold = 4;
+				dragEl.draggable = true;
+			}
+
+			pluginEvent('delayStart', this, { evt });
+
+			// Delay is impossible for native DnD in Edge or IE
+			if (options.delay && (!options.delayOnTouchOnly || touch) && (!this.nativeDraggable || !(Edge || IE11OrLess))) {
+				if (Sortable.eventCanceled) {
+					this._onDrop();
+					return;
+				}
+				// If the user moves the pointer or let go the click or touch
+				// before the delay has been reached:
+				// disable the delayed drag
+				on(ownerDocument, 'mouseup', _this._disableDelayedDrag);
+				on(ownerDocument, 'touchend', _this._disableDelayedDrag);
+				on(ownerDocument, 'touchcancel', _this._disableDelayedDrag);
+				on(ownerDocument, 'mousemove', _this._delayedDragTouchMoveHandler);
+				on(ownerDocument, 'touchmove', _this._delayedDragTouchMoveHandler);
+				options.supportPointer && on(ownerDocument, 'pointermove', _this._delayedDragTouchMoveHandler);
+
+				_this._dragStartTimer = setTimeout(dragStartFn, options.delay);
+			} else {
+				dragStartFn();
+			}
+		}
+	},
+
+	_delayedDragTouchMoveHandler: function (/** TouchEvent|PointerEvent **/e) {
+		let touch = e.touches ? e.touches[0] : e;
+		if (Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY))
+				>= Math.floor(this.options.touchStartThreshold / (this.nativeDraggable && window.devicePixelRatio || 1))
+		) {
+			this._disableDelayedDrag();
+		}
+	},
+
+	_disableDelayedDrag: function () {
+		dragEl && _disableDraggable(dragEl);
+		clearTimeout(this._dragStartTimer);
+
+		this._disableDelayedDragEvents();
+	},
+
+	_disableDelayedDragEvents: function () {
+		let ownerDocument = this.el.ownerDocument;
+		off(ownerDocument, 'mouseup', this._disableDelayedDrag);
+		off(ownerDocument, 'touchend', this._disableDelayedDrag);
+		off(ownerDocument, 'touchcancel', this._disableDelayedDrag);
+		off(ownerDocument, 'mousemove', this._delayedDragTouchMoveHandler);
+		off(ownerDocument, 'touchmove', this._delayedDragTouchMoveHandler);
+		off(ownerDocument, 'pointermove', this._delayedDragTouchMoveHandler);
+	},
+
+	_triggerDragStart: function (/** Event */evt, /** Touch */touch) {
+		touch = touch || (evt.pointerType == 'touch' && evt);
+
+		if (!this.nativeDraggable || touch) {
+			if (this.options.supportPointer) {
+				on(document, 'pointermove', this._onTouchMove);
+			} else if (touch) {
+				on(document, 'touchmove', this._onTouchMove);
+			} else {
+				on(document, 'mousemove', this._onTouchMove);
+			}
+		} else {
+			on(dragEl, 'dragend', this);
+			on(rootEl, 'dragstart', this._onDragStart);
+		}
+
+		try {
+			if (document.selection) {
+				// Timeout neccessary for IE9
+				_nextTick(function () {
+					document.selection.empty();
+				});
+			} else {
+				window.getSelection().removeAllRanges();
+			}
+		} catch (err) {
+		}
+	},
+
+	_dragStarted: function (fallback, evt) {
+		let _this = this;
+		awaitingDragStarted = false;
+		if (rootEl && dragEl) {
+			pluginEvent('dragStarted', this, { evt });
+
+			if (this.nativeDraggable) {
+				on(document, 'dragover', _checkOutsideTargetEl);
+			}
+			let options = this.options;
+
+			// Apply effect
+			!fallback && toggleClass(dragEl, options.dragClass, false);
+			toggleClass(dragEl, options.ghostClass, true);
+
+			Sortable.active = this;
+
+			fallback && this._appendGhost();
+
+			// Drag start event
+			_dispatchEvent({
+				sortable: this,
+				name: 'start',
+				originalEvent: evt
+			});
+		} else {
+			this._nulling();
+		}
+	},
+
+	_emulateDragOver: function () {
+		if (touchEvt) {
+			this._lastX = touchEvt.clientX;
+			this._lastY = touchEvt.clientY;
+
+			_hideGhostForTarget();
+
+			let target = document.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+			let parent = target;
+
+			while (target && target.shadowRoot) {
+				target = target.shadowRoot.elementFromPoint(touchEvt.clientX, touchEvt.clientY);
+				if (target === parent) break;
+				parent = target;
+			}
+
+			dragEl.parentNode[expando]._isOutsideThisEl(target);
+
+			if (parent) {
+				do {
+					if (parent[expando]) {
+						let inserted;
+
+						inserted = parent[expando]._onDragOver({
+							clientX: touchEvt.clientX,
+							clientY: touchEvt.clientY,
+							target: target,
+							rootEl: parent
+						});
+
+						if (inserted && !this.options.dragoverBubble) {
+							break;
+						}
+					}
+
+					target = parent; // store last element
+				}
+				/* jshint boss:true */
+				while (parent = parent.parentNode);
+			}
+
+			_unhideGhostForTarget();
+		}
+	},
+
+
+	_onTouchMove: function (/**TouchEvent*/evt) {
+		if (tapEvt) {
+			let	options = this.options,
+				fallbackTolerance = options.fallbackTolerance,
+				fallbackOffset = options.fallbackOffset,
+				touch = evt.touches ? evt.touches[0] : evt,
+				ghostMatrix = ghostEl && matrix(ghostEl, true),
+				scaleX = ghostEl && ghostMatrix && ghostMatrix.a,
+				scaleY = ghostEl && ghostMatrix && ghostMatrix.d,
+				relativeScrollOffset = PositionGhostAbsolutely && ghostRelativeParent && getRelativeScrollOffset(ghostRelativeParent),
+				dx = ((touch.clientX - tapEvt.clientX)
+						+ fallbackOffset.x) / (scaleX || 1)
+						+ (relativeScrollOffset ? (relativeScrollOffset[0] - ghostRelativeParentInitialScroll[0]) : 0) / (scaleX || 1),
+				dy = ((touch.clientY - tapEvt.clientY)
+						+ fallbackOffset.y) / (scaleY || 1)
+						+ (relativeScrollOffset ? (relativeScrollOffset[1] - ghostRelativeParentInitialScroll[1]) : 0) / (scaleY || 1);
+
+			// only set the status to dragging, when we are actually dragging
+			if (!Sortable.active && !awaitingDragStarted) {
+				if (fallbackTolerance &&
+					Math.max(Math.abs(touch.clientX - this._lastX), Math.abs(touch.clientY - this._lastY)) < fallbackTolerance
+				) {
+					return;
+				}
+				this._onDragStart(evt, true);
+			}
+
+			if (ghostEl) {
+				if (ghostMatrix) {
+					ghostMatrix.e += dx - (lastDx || 0);
+					ghostMatrix.f += dy - (lastDy || 0);
+				} else {
+					ghostMatrix = {
+						a: 1,
+						b: 0,
+						c: 0,
+						d: 1,
+						e: dx,
+						f: dy
+					};
+				}
+
+				let cssMatrix = `matrix(${ghostMatrix.a},${ghostMatrix.b},${ghostMatrix.c},${ghostMatrix.d},${ghostMatrix.e},${ghostMatrix.f})`;
+
+				css(ghostEl, 'webkitTransform', cssMatrix);
+				css(ghostEl, 'mozTransform', cssMatrix);
+				css(ghostEl, 'msTransform', cssMatrix);
+				css(ghostEl, 'transform', cssMatrix);
+
+				lastDx = dx;
+				lastDy = dy;
+
+				touchEvt = touch;
+			}
+
+			evt.cancelable && evt.preventDefault();
+		}
+	},
+
+	_appendGhost: function () {
+		// Bug if using scale(): https://stackoverflow.com/questions/2637058
+		// Not being adjusted for
+		if (!ghostEl) {
+			let container = this.options.fallbackOnBody ? document.body : rootEl,
+				rect = getRect(dragEl, true, PositionGhostAbsolutely, true, container),
+				options = this.options;
+
+			// Position absolutely
+			if (PositionGhostAbsolutely) {
+				// Get relatively positioned parent
+				ghostRelativeParent = container;
+
+				while (
+					css(ghostRelativeParent, 'position') === 'static' &&
+					css(ghostRelativeParent, 'transform') === 'none' &&
+					ghostRelativeParent !== document
+				) {
+					ghostRelativeParent = ghostRelativeParent.parentNode;
+				}
+
+				if (ghostRelativeParent !== document.body && ghostRelativeParent !== document.documentElement) {
+					if (ghostRelativeParent === document) ghostRelativeParent = getWindowScrollingElement();
+
+					rect.top += ghostRelativeParent.scrollTop;
+					rect.left += ghostRelativeParent.scrollLeft;
+				} else {
+					ghostRelativeParent = getWindowScrollingElement();
+				}
+				ghostRelativeParentInitialScroll = getRelativeScrollOffset(ghostRelativeParent);
+			}
+
+
+			ghostEl = dragEl.cloneNode(true);
+
+			toggleClass(ghostEl, options.ghostClass, false);
+			toggleClass(ghostEl, options.fallbackClass, true);
+			toggleClass(ghostEl, options.dragClass, true);
+
+			css(ghostEl, 'transition', '');
+			css(ghostEl, 'transform', '');
+
+			css(ghostEl, 'box-sizing', 'border-box');
+			css(ghostEl, 'margin', 0);
+			css(ghostEl, 'top', rect.top);
+			css(ghostEl, 'left', rect.left);
+			css(ghostEl, 'width', rect.width);
+			css(ghostEl, 'height', rect.height);
+			css(ghostEl, 'opacity', '0.8');
+			css(ghostEl, 'position', (PositionGhostAbsolutely ? 'absolute' : 'fixed'));
+			css(ghostEl, 'zIndex', '100000');
+			css(ghostEl, 'pointerEvents', 'none');
+
+
+			Sortable.ghost = ghostEl;
+
+			container.appendChild(ghostEl);
+
+			// Set transform-origin
+			css(ghostEl, 'transform-origin', (tapDistanceLeft / parseInt(ghostEl.style.width) * 100) + '% ' + (tapDistanceTop / parseInt(ghostEl.style.height) * 100) + '%');
+		}
+	},
+
+	_onDragStart: function (/**Event*/evt, /**boolean*/fallback) {
+		let _this = this;
+		let dataTransfer = evt.dataTransfer;
+		let options = _this.options;
+
+		pluginEvent('dragStart', this, { evt });
+		if (Sortable.eventCanceled) {
+			this._onDrop();
+			return;
+		}
+
+		pluginEvent('setupClone', this);
+		if (!Sortable.eventCanceled) {
+			cloneEl = clone(dragEl);
+
+			cloneEl.draggable = false;
+			cloneEl.style['will-change'] = '';
+
+			this._hideClone();
+
+			toggleClass(cloneEl, this.options.chosenClass, false);
+			Sortable.clone = cloneEl;
+		}
+
+
+		// #1143: IFrame support workaround
+		_this.cloneId = _nextTick(function() {
+			pluginEvent('clone', _this);
+			if (Sortable.eventCanceled) return;
+
+			if (!_this.options.removeCloneOnHide) {
+				rootEl.insertBefore(cloneEl, dragEl);
+			}
+			_this._hideClone();
+
+			_dispatchEvent({
+				sortable: _this,
+				name: 'clone'
+			});
+		});
+
+
+		!fallback && toggleClass(dragEl, options.dragClass, true);
+
+		// Set proper drop events
+		if (fallback) {
+			ignoreNextClick = true;
+			_this._loopId = setInterval(_this._emulateDragOver, 50);
+		} else {
+			// Undo what was set in _prepareDragStart before drag started
+			off(document, 'mouseup', _this._onDrop);
+			off(document, 'touchend', _this._onDrop);
+			off(document, 'touchcancel', _this._onDrop);
+
+			if (dataTransfer) {
+				dataTransfer.effectAllowed = 'move';
+				options.setData && options.setData.call(_this, dataTransfer, dragEl);
+			}
+
+			on(document, 'drop', _this);
+
+			// #1276 fix:
+			css(dragEl, 'transform', 'translateZ(0)');
+		}
+
+		awaitingDragStarted = true;
+
+		_this._dragStartId = _nextTick(_this._dragStarted.bind(_this, fallback, evt));
+		on(document, 'selectstart', _this);
+
+		moved = true;
+
+		if (Safari) {
+			css(document.body, 'user-select', 'none');
+		}
+	},
+
+
+	// Returns true - if no further action is needed (either inserted or another condition)
+	_onDragOver: function (/**Event*/evt) {
+		let el = this.el,
+			target = evt.target,
+			dragRect,
+			targetRect,
+			revert,
+			options = this.options,
+			group = options.group,
+			activeSortable = Sortable.active,
+			isOwner = (activeGroup === group),
+			canSort = options.sort,
+			fromSortable = (putSortable || activeSortable),
+			vertical,
+			_this = this,
+			completedFired = false;
+
+		if (_silent) return;
+
+		function dragOverEvent(name, extra) {
+			pluginEvent(name, _this, {
+				evt,
+				isOwner,
+				axis: vertical ? 'vertical' : 'horizontal',
+				revert,
+				dragRect,
+				targetRect,
+				canSort,
+				fromSortable,
+				target,
+				completed,
+				onMove(target, after) {
+					return onMove(rootEl, el, dragEl, dragRect, target, getRect(target), evt, after);
+				},
+				changed,
+				...extra
+			});
+		}
+
+		// Capture animation state
+		function capture() {
+			dragOverEvent('dragOverAnimationCapture');
+
+			_this.captureAnimationState();
+			if (_this !== fromSortable) {
+				fromSortable.captureAnimationState();
+			}
+		}
+
+		// Return invocation when dragEl is inserted (or completed)
+		function completed(insertion) {
+			dragOverEvent('dragOverCompleted', { insertion });
+
+			if (insertion) {
+				// Clones must be hidden before folding animation to capture dragRectAbsolute properly
+				if (isOwner) {
+					activeSortable._hideClone();
+				} else {
+					activeSortable._showClone(_this);
+				}
+
+				if (_this !== fromSortable) {
+					// Set ghost class to new sortable's ghost class
+					toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : activeSortable.options.ghostClass, false);
+					toggleClass(dragEl, options.ghostClass, true);
+				}
+
+				if (putSortable !== _this && _this !== Sortable.active) {
+					putSortable = _this;
+				} else if (_this === Sortable.active && putSortable) {
+					putSortable = null;
+				}
+
+				// Animation
+				if (fromSortable === _this) {
+					_this._ignoreWhileAnimating = target;
+				}
+				_this.animateAll(function() {
+					dragOverEvent('dragOverAnimationComplete');
+					_this._ignoreWhileAnimating = null;
+				});
+				if (_this !== fromSortable) {
+					fromSortable.animateAll();
+					fromSortable._ignoreWhileAnimating = null;
+				}
+			}
+
+
+			// Null lastTarget if it is not inside a previously swapped element
+			if ((target === dragEl && !dragEl.animated) || (target === el && !target.animated)) {
+				lastTarget = null;
+			}
+
+			// no bubbling and not fallback
+			if (!options.dragoverBubble && !evt.rootEl && target !== document) {
+				dragEl.parentNode[expando]._isOutsideThisEl(evt.target);
+
+				// Do not detect for empty insert if already inserted
+				!insertion && nearestEmptyInsertDetectEvent(evt);
+			}
+
+			!options.dragoverBubble && evt.stopPropagation && evt.stopPropagation();
+
+			return (completedFired = true);
+		}
+
+		// Call when dragEl has been inserted
+		function changed() {
+			newIndex = index(dragEl);
+			newDraggableIndex = index(dragEl, options.draggable);
+			_dispatchEvent({
+				sortable: _this,
+				name: 'change',
+				toEl: el,
+				newIndex,
+				newDraggableIndex,
+				originalEvent: evt
+			});
+		}
+
+
+		if (evt.preventDefault !== void 0) {
+			evt.cancelable && evt.preventDefault();
+		}
+
+
+		target = closest(target, options.draggable, el, true);
+
+		dragOverEvent('dragOver');
+		if (Sortable.eventCanceled) return completedFired;
+
+		if (
+			dragEl.contains(evt.target) ||
+			target.animated && target.animatingX && target.animatingY ||
+			_this._ignoreWhileAnimating === target
+		) {
+			return completed(false);
+		}
+
+		ignoreNextClick = false;
+
+		if (activeSortable && !options.disabled &&
+			(isOwner
+				? canSort || (revert = !rootEl.contains(dragEl)) // Reverting item into the original list
+				: (
+					putSortable === this ||
+					(
+						(this.lastPutMode = activeGroup.checkPull(this, activeSortable, dragEl, evt)) &&
+						group.checkPut(this, activeSortable, dragEl, evt)
+					)
+				)
+			)
+		) {
+			vertical = this._getDirection(evt, target) === 'vertical';
+
+			dragRect = getRect(dragEl);
+
+			dragOverEvent('dragOverValid');
+			if (Sortable.eventCanceled) return completedFired;
+
+			if (revert) {
+				parentEl = rootEl; // actualization
+				capture();
+
+				this._hideClone();
+
+				dragOverEvent('revert');
+
+				if (!Sortable.eventCanceled) {
+					if (nextEl) {
+						rootEl.insertBefore(dragEl, nextEl);
+					} else {
+						rootEl.appendChild(dragEl);
+					}
+				}
+
+				return completed(true);
+			}
+
+			let elLastChild = lastChild(el, options.draggable);
+
+			if (!elLastChild || _ghostIsLast(evt, vertical, this) && !elLastChild.animated) {
+				// If already at end of list: Do not insert
+				if (elLastChild === dragEl) {
+					return completed(false);
+				}
+
+				// assign target only if condition is true
+				if (elLastChild && el === evt.target) {
+					target = elLastChild;
+				}
+
+				if (target) {
+					targetRect = getRect(target);
+				}
+
+				if (onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, !!target) !== false) {
+					capture();
+					el.appendChild(dragEl);
+					parentEl = el; // actualization
+
+					changed();
+					return completed(true);
+				}
+			}
+			else if (target.parentNode === el) {
+				targetRect = getRect(target);
+				let direction = 0,
+					targetBeforeFirstSwap,
+					differentLevel = dragEl.parentNode !== el,
+					differentRowCol = !_dragElInRowColumn(dragEl.animated && dragEl.toRect || dragRect, target.animated && target.toRect || targetRect, vertical),
+					side1 = vertical ? 'top' : 'left',
+					scrolledPastTop = isScrolledPast(target, 'top', 'top') || isScrolledPast(dragEl, 'top', 'top'),
+					scrollBefore = scrolledPastTop ? scrolledPastTop.scrollTop : void 0;
+
+
+				if (lastTarget !== target) {
+					targetBeforeFirstSwap = targetRect[side1];
+					pastFirstInvertThresh = false;
+					isCircumstantialInvert = (!differentRowCol && options.invertSwap) || differentLevel;
+				}
+
+				direction = _getSwapDirection(
+					evt, target, targetRect, vertical,
+					differentRowCol ? 1 : options.swapThreshold,
+					options.invertedSwapThreshold == null ? options.swapThreshold : options.invertedSwapThreshold,
+					isCircumstantialInvert,
+					lastTarget === target
+				);
+
+				let sibling;
+
+				if (direction !== 0) {
+					// Check if target is beside dragEl in respective direction (ignoring hidden elements)
+					let dragIndex = index(dragEl);
+
+					do {
+						dragIndex -= direction;
+						sibling = parentEl.children[dragIndex];
+					} while (sibling && (css(sibling, 'display') === 'none' || sibling === ghostEl));
+				}
+				// If dragEl is already beside target: Do not insert
+				if (
+					direction === 0 ||
+					sibling === target
+				) {
+					return completed(false);
+				}
+
+				lastTarget = target;
+
+				lastDirection = direction;
+
+				let nextSibling = target.nextElementSibling,
+					after = false;
+
+				after = direction === 1;
+
+				let moveVector = onMove(rootEl, el, dragEl, dragRect, target, targetRect, evt, after);
+
+				if (moveVector !== false) {
+					if (moveVector === 1 || moveVector === -1) {
+						after = (moveVector === 1);
+					}
+
+					_silent = true;
+					setTimeout(_unsilent, 30);
+
+					capture();
+
+					if (after && !nextSibling) {
+						el.appendChild(dragEl);
+					} else {
+						target.parentNode.insertBefore(dragEl, after ? nextSibling : target);
+					}
+
+					// Undo chrome's scroll adjustment (has no effect on other browsers)
+					if (scrolledPastTop) {
+						scrollBy(scrolledPastTop, 0, scrollBefore - scrolledPastTop.scrollTop);
+					}
+
+					parentEl = dragEl.parentNode; // actualization
+
+					// must be done before animation
+					if (targetBeforeFirstSwap !== undefined && !isCircumstantialInvert) {
+						targetMoveDistance = Math.abs(targetBeforeFirstSwap - getRect(target)[side1]);
+					}
+					changed();
+
+					return completed(true);
+				}
+			}
+
+			if (el.contains(dragEl)) {
+				return completed(false);
+			}
+		}
+
+		return false;
+	},
+
+	_ignoreWhileAnimating: null,
+
+	_offMoveEvents: function() {
+		off(document, 'mousemove', this._onTouchMove);
+		off(document, 'touchmove', this._onTouchMove);
+		off(document, 'pointermove', this._onTouchMove);
+		off(document, 'dragover', nearestEmptyInsertDetectEvent);
+		off(document, 'mousemove', nearestEmptyInsertDetectEvent);
+		off(document, 'touchmove', nearestEmptyInsertDetectEvent);
+	},
+
+	_offUpEvents: function () {
+		let ownerDocument = this.el.ownerDocument;
+
+		off(ownerDocument, 'mouseup', this._onDrop);
+		off(ownerDocument, 'touchend', this._onDrop);
+		off(ownerDocument, 'pointerup', this._onDrop);
+		off(ownerDocument, 'touchcancel', this._onDrop);
+		off(document, 'selectstart', this);
+	},
+
+	_onDrop: function (/**Event*/evt) {
+		let el = this.el,
+			options = this.options;
+
+		// Get the index of the dragged element within its parent
+		newIndex = index(dragEl);
+		newDraggableIndex = index(dragEl, options.draggable);
+
+		pluginEvent('drop', this, {
+			evt
+		});
+
+		parentEl = dragEl && dragEl.parentNode;
+
+		// Get again after plugin event
+		newIndex = index(dragEl);
+		newDraggableIndex = index(dragEl, options.draggable);
+
+		if (Sortable.eventCanceled) {
+			this._nulling();
+			return;
+		}
+
+		awaitingDragStarted = false;
+		isCircumstantialInvert = false;
+		pastFirstInvertThresh = false;
+
+		clearInterval(this._loopId);
+
+		clearTimeout(this._dragStartTimer);
+
+		_cancelNextTick(this.cloneId);
+		_cancelNextTick(this._dragStartId);
+
+		// Unbind events
+		if (this.nativeDraggable) {
+			off(document, 'drop', this);
+			off(el, 'dragstart', this._onDragStart);
+		}
+		this._offMoveEvents();
+		this._offUpEvents();
+
+
+		if (Safari) {
+			css(document.body, 'user-select', '');
+		}
+
+		css(dragEl, 'transform', '');
+
+		if (evt) {
+			if (moved) {
+				evt.cancelable && evt.preventDefault();
+				!options.dropBubble && evt.stopPropagation();
+			}
+
+			ghostEl && ghostEl.parentNode && ghostEl.parentNode.removeChild(ghostEl);
+
+			if (rootEl === parentEl || (putSortable && putSortable.lastPutMode !== 'clone')) {
+				// Remove clone(s)
+				cloneEl && cloneEl.parentNode && cloneEl.parentNode.removeChild(cloneEl);
+			}
+
+			if (dragEl) {
+				if (this.nativeDraggable) {
+					off(dragEl, 'dragend', this);
+				}
+
+				_disableDraggable(dragEl);
+				dragEl.style['will-change'] = '';
+
+				// Remove classes
+				// ghostClass is added in dragStarted
+				if (moved && !awaitingDragStarted) {
+					toggleClass(dragEl, putSortable ? putSortable.options.ghostClass : this.options.ghostClass, false);
+				}
+				toggleClass(dragEl, this.options.chosenClass, false);
+
+				// Drag stop event
+				_dispatchEvent({
+					sortable: this,
+					name: 'unchoose',
+					toEl: parentEl,
+					newIndex: null,
+					newDraggableIndex: null,
+					originalEvent: evt
+				});
+
+
+				if (rootEl !== parentEl) {
+
+					if (newIndex >= 0) {
+						// Add event
+						_dispatchEvent({
+							rootEl: parentEl,
+							name: 'add',
+							toEl: parentEl,
+							fromEl: rootEl,
+							originalEvent: evt
+						});
+
+						// Remove event
+						_dispatchEvent({
+							sortable: this,
+							name: 'remove',
+							toEl: parentEl,
+							originalEvent: evt
+						});
+
+						// drag from one list and drop into another
+						_dispatchEvent({
+							rootEl: parentEl,
+							name: 'sort',
+							toEl: parentEl,
+							fromEl: rootEl,
+							originalEvent: evt
+						});
+
+						_dispatchEvent({
+							sortable: this,
+							name: 'sort',
+							toEl: parentEl,
+							originalEvent: evt
+						});
+					}
+
+					putSortable && putSortable.save();
+				} else {
+					if (newIndex !== oldIndex) {
+						if (newIndex >= 0) {
+							// drag & drop within the same list
+							_dispatchEvent({
+								sortable: this,
+								name: 'update',
+								toEl: parentEl,
+								originalEvent: evt
+							});
+
+							_dispatchEvent({
+								sortable: this,
+								name: 'sort',
+								toEl: parentEl,
+								originalEvent: evt
+							});
+						}
+					}
+				}
+
+				if (Sortable.active) {
+					/* jshint eqnull:true */
+					if (newIndex == null || newIndex === -1) {
+						newIndex = oldIndex;
+						newDraggableIndex = oldDraggableIndex;
+					}
+
+					_dispatchEvent({
+						sortable: this,
+						name: 'end',
+						toEl: parentEl,
+						originalEvent: evt
+					});
+
+					// Save sorting
+					this.save();
+				}
+			}
+
+		}
+		this._nulling();
+	},
+
+	_nulling: function() {
+		pluginEvent('nulling', this);
+
+		rootEl =
+		dragEl =
+		parentEl =
+		ghostEl =
+		nextEl =
+		cloneEl =
+		lastDownEl =
+		cloneHidden =
+
+		tapEvt =
+		touchEvt =
+
+		moved =
+		newIndex =
+		newDraggableIndex =
+		oldIndex =
+		oldDraggableIndex =
+
+		lastTarget =
+		lastDirection =
+
+		putSortable =
+		activeGroup =
+		Sortable.dragged =
+		Sortable.ghost =
+		Sortable.clone =
+		Sortable.active = null;
+
+		savedInputChecked.forEach(function (el) {
+			el.checked = true;
+		});
+
+		savedInputChecked.length =
+		lastDx =
+		lastDy = 0;
+	},
+
+	handleEvent: function (/**Event*/evt) {
+		switch (evt.type) {
+			case 'drop':
+			case 'dragend':
+				this._onDrop(evt);
+				break;
+
+			case 'dragenter':
+			case 'dragover':
+				if (dragEl) {
+					this._onDragOver(evt);
+					_globalDragOver(evt);
+				}
+				break;
+
+			case 'selectstart':
+				evt.preventDefault();
+				break;
+		}
+	},
+
+
+	/**
+	 * Serializes the item into an array of string.
+	 * @returns {String[]}
+	 */
+	toArray: function () {
+		let order = [],
+			el,
+			children = this.el.children,
+			i = 0,
+			n = children.length,
+			options = this.options;
+
+		for (; i < n; i++) {
+			el = children[i];
+			if (closest(el, options.draggable, this.el, false)) {
+				order.push(el.getAttribute(options.dataIdAttr) || _generateId(el));
+			}
+		}
+
+		return order;
+	},
+
+
+	/**
+	 * Sorts the elements according to the array.
+	 * @param  {String[]}  order  order of the items
+	 */
+	sort: function (order) {
+		let items = {}, rootEl = this.el;
+
+		this.toArray().forEach(function (id, i) {
+			let el = rootEl.children[i];
+
+			if (closest(el, this.options.draggable, rootEl, false)) {
+				items[id] = el;
+			}
+		}, this);
+
+		order.forEach(function (id) {
+			if (items[id]) {
+				rootEl.removeChild(items[id]);
+				rootEl.appendChild(items[id]);
+			}
+		});
+	},
+
+
+	/**
+	 * Save the current sorting
+	 */
+	save: function () {
+		let store = this.options.store;
+		store && store.set && store.set(this);
+	},
+
+
+	/**
+	 * For each element in the set, get the first element that matches the selector by testing the element itself and traversing up through its ancestors in the DOM tree.
+	 * @param   {HTMLElement}  el
+	 * @param   {String}       [selector]  default: `options.draggable`
+	 * @returns {HTMLElement|null}
+	 */
+	closest: function (el, selector) {
+		return closest(el, selector || this.options.draggable, this.el, false);
+	},
+
+
+	/**
+	 * Set/get option
+	 * @param   {string} name
+	 * @param   {*}      [value]
+	 * @returns {*}
+	 */
+	option: function (name, value) {
+		let options = this.options;
+
+		if (value === void 0) {
+			return options[name];
+		} else {
+			let modifiedValue = PluginManager.modifyOption(this, name, value);
+			if (typeof modifiedValue !== 'undefined') {
+				options[name] = modifiedValue;
+			} else {
+				options[name] = value;
+			}
+
+			if (name === 'group') {
+				_prepareGroup(options);
+			}
+		}
+	},
+
+
+	/**
+	 * Destroy
+	 */
+	destroy: function () {
+		pluginEvent('destroy', this);
+		let el = this.el;
+
+		el[expando] = null;
+
+		off(el, 'mousedown', this._onTapStart);
+		off(el, 'touchstart', this._onTapStart);
+		off(el, 'pointerdown', this._onTapStart);
+
+		if (this.nativeDraggable) {
+			off(el, 'dragover', this);
+			off(el, 'dragenter', this);
+		}
+		// Remove draggable attributes
+		Array.prototype.forEach.call(el.querySelectorAll('[draggable]'), function (el) {
+			el.removeAttribute('draggable');
+		});
+
+		this._onDrop();
+
+		this._disableDelayedDragEvents();
+
+		sortables.splice(sortables.indexOf(this.el), 1);
+
+		this.el = el = null;
+	},
+
+	_hideClone: function() {
+		if (!cloneHidden) {
+			pluginEvent('hideClone', this);
+			if (Sortable.eventCanceled) return;
+
+
+			css(cloneEl, 'display', 'none');
+			if (this.options.removeCloneOnHide && cloneEl.parentNode) {
+				cloneEl.parentNode.removeChild(cloneEl);
+			}
+			cloneHidden = true;
+		}
+	},
+
+	_showClone: function(putSortable) {
+		if (putSortable.lastPutMode !== 'clone') {
+			this._hideClone();
+			return;
+		}
+
+
+		if (cloneHidden) {
+			pluginEvent('showClone', this);
+			if (Sortable.eventCanceled) return;
+
+			// show clone at dragEl or original position
+			if (rootEl.contains(dragEl) && !this.options.group.revertClone) {
+				rootEl.insertBefore(cloneEl, dragEl);
+			} else if (nextEl) {
+				rootEl.insertBefore(cloneEl, nextEl);
+			} else {
+				rootEl.appendChild(cloneEl);
+			}
+
+			if (this.options.group.revertClone) {
+				this.animate(dragEl, cloneEl);
+			}
+
+			css(cloneEl, 'display', '');
+			cloneHidden = false;
+		}
+	}
+};
+
+function _globalDragOver(/**Event*/evt) {
+	if (evt.dataTransfer) {
+		evt.dataTransfer.dropEffect = 'move';
+	}
+	evt.cancelable && evt.preventDefault();
+}
+
+function onMove(fromEl, toEl, dragEl, dragRect, targetEl, targetRect, originalEvent, willInsertAfter) {
+	let evt,
+		sortable = fromEl[expando],
+		onMoveFn = sortable.options.onMove,
+		retVal;
+	// Support for new CustomEvent feature
+	if (window.CustomEvent && !IE11OrLess && !Edge) {
+		evt = new CustomEvent('move', {
+			bubbles: true,
+			cancelable: true
+		});
+	} else {
+		evt = document.createEvent('Event');
+		evt.initEvent('move', true, true);
+	}
+
+	evt.to = toEl;
+	evt.from = fromEl;
+	evt.dragged = dragEl;
+	evt.draggedRect = dragRect;
+	evt.related = targetEl || toEl;
+	evt.relatedRect = targetRect || getRect(toEl);
+	evt.willInsertAfter = willInsertAfter;
+
+	evt.originalEvent = originalEvent;
+
+	fromEl.dispatchEvent(evt);
+
+	if (onMoveFn) {
+		retVal = onMoveFn.call(sortable, evt, originalEvent);
+	}
+
+	return retVal;
+}
+
+function _disableDraggable(el) {
+	el.draggable = false;
+}
+
+function _unsilent() {
+	_silent = false;
+}
+
+
+function _ghostIsLast(evt, vertical, sortable) {
+	let rect = getRect(lastChild(sortable.el, sortable.options.draggable));
+	const spacer = 10;
+
+	return vertical ?
+		(evt.clientX > rect.right + spacer || evt.clientX <= rect.right && evt.clientY > rect.bottom && evt.clientX >= rect.left) :
+		(evt.clientX > rect.right && evt.clientY > rect.top || evt.clientX <= rect.right && evt.clientY > rect.bottom + spacer);
+}
+
+function _getSwapDirection(evt, target, targetRect, vertical, swapThreshold, invertedSwapThreshold, invertSwap, isLastTarget) {
+	let mouseOnAxis = vertical ? evt.clientY : evt.clientX,
+		targetLength = vertical ? targetRect.height : targetRect.width,
+		targetS1 = vertical ? targetRect.top : targetRect.left,
+		targetS2 = vertical ? targetRect.bottom : targetRect.right,
+		invert = false;
+
+
+	if (!invertSwap) {
+		// Never invert or create dragEl shadow when target movemenet causes mouse to move past the end of regular swapThreshold
+		if (isLastTarget && targetMoveDistance < targetLength * swapThreshold) { // multiplied only by swapThreshold because mouse will already be inside target by (1 - threshold) * targetLength / 2
+			// check if past first invert threshold on side opposite of lastDirection
+			if (!pastFirstInvertThresh &&
+				(lastDirection === 1 ?
+					(
+						mouseOnAxis > targetS1 + targetLength * invertedSwapThreshold / 2
+					) :
+					(
+						mouseOnAxis < targetS2 - targetLength * invertedSwapThreshold / 2
+					)
+				)
+			)
+			{
+				// past first invert threshold, do not restrict inverted threshold to dragEl shadow
+				pastFirstInvertThresh = true;
+			}
+
+			if (!pastFirstInvertThresh) {
+				// dragEl shadow (target move distance shadow)
+				if (
+					lastDirection === 1 ?
+					(
+						mouseOnAxis < targetS1 + targetMoveDistance // over dragEl shadow
+					) :
+					(
+						mouseOnAxis > targetS2 - targetMoveDistance
+					)
+				)
+				{
+					return -lastDirection;
+				}
+			} else {
+				invert = true;
+			}
+		} else {
+			// Regular
+			if (
+				mouseOnAxis > targetS1 + (targetLength * (1 - swapThreshold) / 2) &&
+				mouseOnAxis < targetS2 - (targetLength * (1 - swapThreshold) / 2)
+			) {
+				return _getInsertDirection(target);
+			}
+		}
+	}
+
+	invert = invert || invertSwap;
+
+	if (invert) {
+		// Invert of regular
+		if (
+			mouseOnAxis < targetS1 + (targetLength * invertedSwapThreshold / 2) ||
+			mouseOnAxis > targetS2 - (targetLength * invertedSwapThreshold / 2)
+		)
+		{
+			return ((mouseOnAxis > targetS1 + targetLength / 2) ? 1 : -1);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * Gets the direction dragEl must be swapped relative to target in order to make it
+ * seem that dragEl has been "inserted" into that element's position
+ * @param  {HTMLElement} target       The target whose position dragEl is being inserted at
+ * @return {Number}                   Direction dragEl must be swapped
+ */
+function _getInsertDirection(target) {
+	if (index(dragEl) < index(target)) {
+		return 1;
+	} else {
+		return -1;
+	}
+}
+
+
+/**
+ * Generate id
+ * @param   {HTMLElement} el
+ * @returns {String}
+ * @private
+ */
+function _generateId(el) {
+	let str = el.tagName + el.className + el.src + el.href + el.textContent,
+		i = str.length,
+		sum = 0;
+
+	while (i--) {
+		sum += str.charCodeAt(i);
+	}
+
+	return sum.toString(36);
+}
+
+function _saveInputCheckedState(root) {
+	savedInputChecked.length = 0;
+
+	let inputs = root.getElementsByTagName('input');
+	let idx = inputs.length;
+
+	while (idx--) {
+		let el = inputs[idx];
+		el.checked && savedInputChecked.push(el);
+	}
+}
+
+function _nextTick(fn) {
+	return setTimeout(fn, 0);
+}
+
+function _cancelNextTick(id) {
+	return clearTimeout(id);
+}
+
+// Fixed #973:
+if (documentExists) {
+	on(document, 'touchmove', function(evt) {
+		if ((Sortable.active || awaitingDragStarted) && evt.cancelable) {
+			evt.preventDefault();
+		}
+	});
+}
+
+
+// Export utils
+Sortable.utils = {
+	on: on,
+	off: off,
+	css: css,
+	find: find,
+	is: function (el, selector) {
+		return !!closest(el, selector, el, false);
+	},
+	extend: extend,
+	throttle: throttle,
+	closest: closest,
+	toggleClass: toggleClass,
+	clone: clone,
+	index: index,
+	nextTick: _nextTick,
+	cancelNextTick: _cancelNextTick,
+	detectDirection: _detectDirection,
+	getChild: getChild
+};
+
+
+/**
+ * Get the Sortable instance of an element
+ * @param  {HTMLElement} element The element
+ * @return {Sortable|undefined}         The instance of Sortable
+ */
+Sortable.get = function(element) {
+	return element[expando];
+};
+
+/**
+ * Mount a plugin to Sortable
+ * @param  {...SortablePlugin|SortablePlugin[]} plugins       Plugins being mounted
+ */
+Sortable.mount = function(...plugins) {
+	if (plugins[0].constructor === Array) plugins = plugins[0];
+
+	plugins.forEach((plugin) => {
+		if (!plugin.prototype || !plugin.prototype.constructor) {
+			throw `Sortable: Mounted plugin must be a constructor function, not ${ {}.toString.call(plugin) }`;
+		}
+		if (plugin.utils) Sortable.utils = { ...Sortable.utils, ...plugin.utils };
+
+		PluginManager.mount(plugin);
+	});
+};
+
+
+
+/**
+ * Create sortable instance
+ * @param {HTMLElement}  el
+ * @param {Object}      [options]
+ */
+Sortable.create = function (el, options) {
+	return new Sortable(el, options);
+};
+
+
+// Export
+Sortable.version = version;
+
+
+export default Sortable;

+ 556 - 0
public/assets/libs/Sortable/src/utils.js

@@ -0,0 +1,556 @@
+import { IE11OrLess } from './BrowserInfo.js';
+import Sortable from './Sortable.js';
+
+const captureMode = {
+	capture: false,
+	passive: false
+};
+
+function on(el, event, fn) {
+	el.addEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+
+function off(el, event, fn) {
+	el.removeEventListener(event, fn, !IE11OrLess && captureMode);
+}
+
+function matches(/**HTMLElement*/el, /**String*/selector) {
+	if (!selector) return;
+
+	selector[0] === '>' && (selector = selector.substring(1));
+
+	if (el) {
+		try {
+			if (el.matches) {
+				return el.matches(selector);
+			} else if (el.msMatchesSelector) {
+				return el.msMatchesSelector(selector);
+			} else if (el.webkitMatchesSelector) {
+				return el.webkitMatchesSelector(selector);
+			}
+		} catch(_) {
+			return false;
+		}
+	}
+
+	return false;
+}
+
+function getParentOrHost(el) {
+	return (el.host && el !== document && el.host.nodeType)
+		? el.host
+		: el.parentNode;
+}
+
+function closest(/**HTMLElement*/el, /**String*/selector, /**HTMLElement*/ctx, includeCTX) {
+	if (el) {
+		ctx = ctx || document;
+
+		do {
+			if (
+				selector != null &&
+				(
+					selector[0] === '>' ?
+					el.parentNode === ctx && matches(el, selector) :
+					matches(el, selector)
+				) ||
+				includeCTX && el === ctx
+			) {
+				return el;
+			}
+
+			if (el === ctx) break;
+			/* jshint boss:true */
+		} while (el = getParentOrHost(el));
+	}
+
+	return null;
+}
+
+const R_SPACE = /\s+/g;
+
+function toggleClass(el, name, state) {
+	if (el && name) {
+		if (el.classList) {
+			el.classList[state ? 'add' : 'remove'](name);
+		}
+		else {
+			let className = (' ' + el.className + ' ').replace(R_SPACE, ' ').replace(' ' + name + ' ', ' ');
+			el.className = (className + (state ? ' ' + name : '')).replace(R_SPACE, ' ');
+		}
+	}
+}
+
+
+function css(el, prop, val) {
+	let style = el && el.style;
+
+	if (style) {
+		if (val === void 0) {
+			if (document.defaultView && document.defaultView.getComputedStyle) {
+				val = document.defaultView.getComputedStyle(el, '');
+			}
+			else if (el.currentStyle) {
+				val = el.currentStyle;
+			}
+
+			return prop === void 0 ? val : val[prop];
+		}
+		else {
+			if (!(prop in style) && prop.indexOf('webkit') === -1) {
+				prop = '-webkit-' + prop;
+			}
+
+			style[prop] = val + (typeof val === 'string' ? '' : 'px');
+		}
+	}
+}
+
+function matrix(el, selfOnly) {
+	let appliedTransforms = '';
+	if (typeof(el) === 'string') {
+		appliedTransforms = el;
+	} else {
+		do {
+			let transform = css(el, 'transform');
+
+			if (transform && transform !== 'none') {
+				appliedTransforms = transform + ' ' + appliedTransforms;
+			}
+			/* jshint boss:true */
+		} while (!selfOnly && (el = el.parentNode));
+	}
+
+	const matrixFn = window.DOMMatrix || window.WebKitCSSMatrix || window.CSSMatrix || window.MSCSSMatrix;
+	/*jshint -W056 */
+	return matrixFn && (new matrixFn(appliedTransforms));
+}
+
+
+function find(ctx, tagName, iterator) {
+	if (ctx) {
+		let list = ctx.getElementsByTagName(tagName), i = 0, n = list.length;
+
+		if (iterator) {
+			for (; i < n; i++) {
+				iterator(list[i], i);
+			}
+		}
+
+		return list;
+	}
+
+	return [];
+}
+
+
+
+function getWindowScrollingElement() {
+	let scrollingElement = document.scrollingElement;
+
+	if (scrollingElement) {
+		return scrollingElement
+	} else {
+		return document.documentElement
+	}
+}
+
+
+/**
+ * Returns the "bounding client rect" of given element
+ * @param  {HTMLElement} el                       The element whose boundingClientRect is wanted
+ * @param  {[Boolean]} relativeToContainingBlock  Whether the rect should be relative to the containing block of (including) the container
+ * @param  {[Boolean]} relativeToNonStaticParent  Whether the rect should be relative to the relative parent of (including) the contaienr
+ * @param  {[Boolean]} undoScale                  Whether the container's scale() should be undone
+ * @param  {[HTMLElement]} container              The parent the element will be placed in
+ * @return {Object}                               The boundingClientRect of el, with specified adjustments
+ */
+function getRect(el, relativeToContainingBlock, relativeToNonStaticParent, undoScale, container) {
+	if (!el.getBoundingClientRect && el !== window) return;
+
+	let elRect,
+		top,
+		left,
+		bottom,
+		right,
+		height,
+		width;
+
+	if (el !== window && el !== getWindowScrollingElement()) {
+		elRect = el.getBoundingClientRect();
+		top = elRect.top;
+		left = elRect.left;
+		bottom = elRect.bottom;
+		right = elRect.right;
+		height = elRect.height;
+		width = elRect.width;
+	} else {
+		top = 0;
+		left = 0;
+		bottom = window.innerHeight;
+		right = window.innerWidth;
+		height = window.innerHeight;
+		width = window.innerWidth;
+	}
+
+	if ((relativeToContainingBlock || relativeToNonStaticParent) && el !== window) {
+		// Adjust for translate()
+		container = container || el.parentNode;
+
+		// solves #1123 (see: https://stackoverflow.com/a/37953806/6088312)
+		// Not needed on <= IE11
+		if (!IE11OrLess) {
+			do {
+				if (
+					container &&
+					container.getBoundingClientRect &&
+					(
+						css(container, 'transform') !== 'none' ||
+						relativeToNonStaticParent &&
+						css(container, 'position') !== 'static'
+					)
+				) {
+					let containerRect = container.getBoundingClientRect();
+
+					// Set relative to edges of padding box of container
+					top -= containerRect.top + parseInt(css(container, 'border-top-width'));
+					left -= containerRect.left + parseInt(css(container, 'border-left-width'));
+					bottom = top + elRect.height;
+					right = left + elRect.width;
+
+					break;
+				}
+				/* jshint boss:true */
+			} while (container = container.parentNode);
+		}
+	}
+
+	if (undoScale && el !== window) {
+		// Adjust for scale()
+		let elMatrix = matrix(container || el),
+			scaleX = elMatrix && elMatrix.a,
+			scaleY = elMatrix && elMatrix.d;
+
+		if (elMatrix) {
+			top /= scaleY;
+			left /= scaleX;
+
+			width /= scaleX;
+			height /= scaleY;
+
+			bottom = top + height;
+			right = left + width;
+		}
+	}
+
+	return {
+		top: top,
+		left: left,
+		bottom: bottom,
+		right: right,
+		width: width,
+		height: height
+	};
+}
+
+/**
+ * Checks if a side of an element is scrolled past a side of its parents
+ * @param  {HTMLElement}  el           The element who's side being scrolled out of view is in question
+ * @param  {String}       elSide       Side of the element in question ('top', 'left', 'right', 'bottom')
+ * @param  {String}       parentSide   Side of the parent in question ('top', 'left', 'right', 'bottom')
+ * @return {HTMLElement}               The parent scroll element that the el's side is scrolled past, or null if there is no such element
+ */
+function isScrolledPast(el, elSide, parentSide) {
+	let parent = getParentAutoScrollElement(el, true),
+		elSideVal = getRect(el)[elSide];
+
+	/* jshint boss:true */
+	while (parent) {
+		let parentSideVal = getRect(parent)[parentSide],
+			visible;
+
+		if (parentSide === 'top' || parentSide === 'left') {
+			visible = elSideVal >= parentSideVal;
+		} else {
+			visible = elSideVal <= parentSideVal;
+		}
+
+		if (!visible) return parent;
+
+		if (parent === getWindowScrollingElement()) break;
+
+		parent = getParentAutoScrollElement(parent, false);
+	}
+
+	return false;
+}
+
+
+
+/**
+ * Gets nth child of el, ignoring hidden children, sortable's elements (does not ignore clone if it's visible)
+ * and non-draggable elements
+ * @param  {HTMLElement} el       The parent element
+ * @param  {Number} childNum      The index of the child
+ * @param  {Object} options       Parent Sortable's options
+ * @return {HTMLElement}          The child at index childNum, or null if not found
+ */
+function getChild(el, childNum, options) {
+	let currentChild = 0,
+		i = 0,
+		children = el.children;
+
+	while (i < children.length) {
+		if (
+			children[i].style.display !== 'none' &&
+			children[i] !== Sortable.ghost &&
+			children[i] !== Sortable.dragged &&
+			closest(children[i], options.draggable, el, false)
+		) {
+			if (currentChild === childNum) {
+				return children[i];
+			}
+			currentChild++;
+		}
+
+		i++;
+	}
+	return null;
+}
+
+/**
+ * Gets the last child in the el, ignoring ghostEl or invisible elements (clones)
+ * @param  {HTMLElement} el       Parent element
+ * @param  {selector} selector    Any other elements that should be ignored
+ * @return {HTMLElement}          The last child, ignoring ghostEl
+ */
+function lastChild(el, selector) {
+	let last = el.lastElementChild;
+
+	while (
+		last &&
+		(
+			last === Sortable.ghost ||
+			css(last, 'display') === 'none' ||
+			selector && !matches(last, selector)
+		)
+	) {
+		last = last.previousElementSibling;
+	}
+
+	return last || null;
+}
+
+
+/**
+ * Returns the index of an element within its parent for a selected set of
+ * elements
+ * @param  {HTMLElement} el
+ * @param  {selector} selector
+ * @return {number}
+ */
+function index(el, selector) {
+	let index = 0;
+
+	if (!el || !el.parentNode) {
+		return -1;
+	}
+
+	/* jshint boss:true */
+	while (el = el.previousElementSibling) {
+		if ((el.nodeName.toUpperCase() !== 'TEMPLATE') && el !== Sortable.clone && (!selector || matches(el, selector))) {
+			index++;
+		}
+	}
+
+	return index;
+}
+
+/**
+ * Returns the scroll offset of the given element, added with all the scroll offsets of parent elements.
+ * The value is returned in real pixels.
+ * @param  {HTMLElement} el
+ * @return {Array}             Offsets in the format of [left, top]
+ */
+function getRelativeScrollOffset(el) {
+	let offsetLeft = 0,
+		offsetTop = 0,
+		winScroller = getWindowScrollingElement();
+
+	if (el) {
+		do {
+			let elMatrix = matrix(el),
+				scaleX = elMatrix.a,
+				scaleY = elMatrix.d;
+
+			offsetLeft += el.scrollLeft * scaleX;
+			offsetTop += el.scrollTop * scaleY;
+		} while (el !== winScroller && (el = el.parentNode));
+	}
+
+	return [offsetLeft, offsetTop];
+}
+
+/**
+ * Returns the index of the object within the given array
+ * @param  {Array} arr   Array that may or may not hold the object
+ * @param  {Object} obj  An object that has a key-value pair unique to and identical to a key-value pair in the object you want to find
+ * @return {Number}      The index of the object in the array, or -1
+ */
+function indexOfObject(arr, obj) {
+	for (let i in arr) {
+		if (!arr.hasOwnProperty(i)) continue;
+		for (let key in obj) {
+			if (obj.hasOwnProperty(key) && obj[key] === arr[i][key]) return Number(i);
+		}
+	}
+	return -1;
+}
+
+
+function getParentAutoScrollElement(el, includeSelf) {
+	// skip to window
+	if (!el || !el.getBoundingClientRect) return getWindowScrollingElement();
+
+	let elem = el;
+	let gotSelf = false;
+	do {
+		// we don't need to get elem css if it isn't even overflowing in the first place (performance)
+		if (elem.clientWidth < elem.scrollWidth || elem.clientHeight < elem.scrollHeight) {
+			let elemCSS = css(elem);
+			if (
+				elem.clientWidth < elem.scrollWidth && (elemCSS.overflowX == 'auto' || elemCSS.overflowX == 'scroll') ||
+				elem.clientHeight < elem.scrollHeight && (elemCSS.overflowY == 'auto' || elemCSS.overflowY == 'scroll')
+			) {
+				if (!elem.getBoundingClientRect || elem === document.body) return getWindowScrollingElement();
+
+				if (gotSelf || includeSelf) return elem;
+				gotSelf = true;
+			}
+		}
+	/* jshint boss:true */
+	} while (elem = elem.parentNode);
+
+	return getWindowScrollingElement();
+}
+
+function extend(dst, src) {
+	if (dst && src) {
+		for (let key in src) {
+			if (src.hasOwnProperty(key)) {
+				dst[key] = src[key];
+			}
+		}
+	}
+
+	return dst;
+}
+
+
+function isRectEqual(rect1, rect2) {
+	return Math.round(rect1.top) === Math.round(rect2.top) &&
+		Math.round(rect1.left) === Math.round(rect2.left) &&
+		Math.round(rect1.height) === Math.round(rect2.height) &&
+		Math.round(rect1.width) === Math.round(rect2.width);
+}
+
+
+let _throttleTimeout;
+function throttle(callback, ms) {
+	return function () {
+		if (!_throttleTimeout) {
+			let args = arguments,
+				_this = this;
+
+			if (args.length === 1) {
+				callback.call(_this, args[0]);
+			} else {
+				callback.apply(_this, args);
+			}
+
+			_throttleTimeout = setTimeout(function () {
+				_throttleTimeout = void 0;
+			}, ms);
+		}
+	};
+}
+
+
+function cancelThrottle() {
+	clearTimeout(_throttleTimeout);
+	_throttleTimeout = void 0;
+}
+
+
+function scrollBy(el, x, y) {
+	el.scrollLeft += x;
+	el.scrollTop += y;
+}
+
+
+function clone(el) {
+	let Polymer = window.Polymer;
+	let $ = window.jQuery || window.Zepto;
+
+	if (Polymer && Polymer.dom) {
+		return Polymer.dom(el).cloneNode(true);
+	}
+	else if ($) {
+		return $(el).clone(true)[0];
+	}
+	else {
+		return el.cloneNode(true);
+	}
+}
+
+
+function setRect(el, rect) {
+	css(el, 'position', 'absolute');
+	css(el, 'top', rect.top);
+	css(el, 'left', rect.left);
+	css(el, 'width', rect.width);
+	css(el, 'height', rect.height);
+}
+
+function unsetRect(el) {
+	css(el, 'position', '');
+	css(el, 'top', '');
+	css(el, 'left', '');
+	css(el, 'width', '');
+	css(el, 'height', '');
+}
+
+
+const expando = 'Sortable' + (new Date).getTime();
+
+
+export {
+	on,
+	off,
+	matches,
+	getParentOrHost,
+	closest,
+	toggleClass,
+	css,
+	matrix,
+	find,
+	getWindowScrollingElement,
+	getRect,
+	isScrolledPast,
+	getChild,
+	lastChild,
+	index,
+	getRelativeScrollOffset,
+	indexOfObject,
+	getParentAutoScrollElement,
+	extend,
+	isRectEqual,
+	throttle,
+	cancelThrottle,
+	scrollBy,
+	clone,
+	setRect,
+	unsetRect,
+	expando
+};

+ 222 - 0
public/assets/libs/Sortable/st/app.js

@@ -0,0 +1,222 @@
+var example1 = document.getElementById('example1'),
+	example2Left = document.getElementById('example2-left'),
+	example2Right = document.getElementById('example2-right'),
+	example3Left = document.getElementById('example3-left'),
+	example3Right = document.getElementById('example3-right'),
+	example4Left = document.getElementById('example4-left'),
+	example4Right = document.getElementById('example4-right'),
+	example5 = document.getElementById('example5'),
+	example6 = document.getElementById('example6'),
+	example7 = document.getElementById('example7'),
+	gridDemo = document.getElementById('gridDemo'),
+	multiDragDemo = document.getElementById('multiDragDemo'),
+	swapDemo = document.getElementById('swapDemo');
+
+// Example 1 - Simple list
+new Sortable(example1, {
+	animation: 150,
+	ghostClass: 'blue-background-class'
+});
+
+
+// Example 2 - Shared lists
+new Sortable(example2Left, {
+	group: 'shared', // set both lists to same group
+	animation: 150
+});
+
+new Sortable(example2Right, {
+	group: 'shared',
+	animation: 150
+});
+
+// Example 3 - Cloning
+new Sortable(example3Left, {
+	group: {
+		name: 'shared',
+		pull: 'clone' // To clone: set pull to 'clone'
+	},
+	animation: 150
+});
+
+new Sortable(example3Right, {
+	group: {
+		name: 'shared',
+		pull: 'clone'
+	},
+	animation: 150
+});
+
+
+// Example 4 - No Sorting
+new Sortable(example4Left, {
+	group: {
+		name: 'shared',
+		pull: 'clone',
+		put: false // Do not allow items to be put into this list
+	},
+	animation: 150,
+	sort: false // To disable sorting: set sort to false
+});
+
+new Sortable(example4Right, {
+	group: 'shared',
+	animation: 150
+});
+
+
+// Example 5 - Handle
+new Sortable(example5, {
+    handle: '.handle', // handle class
+    animation: 150
+});
+
+// Example 6 - Filter
+new Sortable(example6, {
+    filter: '.filtered',
+    animation: 150
+});
+
+// Example 7 - Thresholds
+var example7Sortable = new Sortable(example7, {
+    animation: 150
+});
+
+
+var example7SwapThreshold = 1;
+var example7SwapThresholdInput = document.getElementById('example7SwapThresholdInput');
+var example7SwapThresholdCode = document.getElementById('example7SwapThresholdCode');
+var example7SwapThresholdIndicators = [].slice.call(document.querySelectorAll('.swap-threshold-indicator'));
+
+var example7InvertSwapInput = document.getElementById('example7InvertSwapInput');
+var example7InvertSwapCode = document.getElementById('example7InvertSwapCode');
+var example7InvertedSwapThresholdIndicators = [].slice.call(document.querySelectorAll('.inverted-swap-threshold-indicator'));
+
+var example7Squares = [].slice.call(document.querySelectorAll('.square'));
+
+var activeIndicators = example7SwapThresholdIndicators;
+
+var example7DirectionInput = document.getElementById('example7DirectionInput');
+var example7SizeProperty = 'width';
+
+
+function renderThresholdWidth(evt) {
+	example7SwapThreshold = Number(evt.target.value);
+	example7SwapThresholdCode.innerHTML = evt.target.value.indexOf('.') > -1 ? evt.target.value.padEnd(4, '0') : evt.target.value;
+
+	for (var i = 0; i < activeIndicators.length; i++) {
+		activeIndicators[i].style[example7SizeProperty] = (evt.target.value * 100) /
+			(activeIndicators == example7SwapThresholdIndicators ? 1 : 2) + '%';
+	}
+
+	example7Sortable.option('swapThreshold', example7SwapThreshold);
+}
+
+example7SwapThresholdInput.addEventListener('input', renderThresholdWidth);
+
+example7InvertSwapInput.addEventListener('input', function(evt) {
+	example7Sortable.option('invertSwap', evt.target.checked);
+
+
+	for (var i = 0; i < activeIndicators.length; i++) {
+		activeIndicators[i].style.display = 'none';
+	}
+
+	if (evt.target.checked) {
+
+		example7InvertSwapCode.style.display = '';
+
+		activeIndicators = example7InvertedSwapThresholdIndicators;
+	} else {
+		example7InvertSwapCode.style.display = 'none';
+		activeIndicators = example7SwapThresholdIndicators;
+	}
+
+	renderThresholdWidth({
+		target: example7SwapThresholdInput
+	});
+
+	for (i = 0; i < activeIndicators.length; i++) {
+		activeIndicators[i].style.display = '';
+	}
+});
+
+function renderDirection(evt) {
+	for (var i = 0; i < example7Squares.length; i++) {
+		example7Squares[i].style.display = evt.target.value === 'h' ? 'inline-block' : 'block';
+	}
+
+	for (i = 0; i < example7InvertedSwapThresholdIndicators.length; i++) {
+		/* jshint expr:true */
+		evt.target.value === 'h' && (example7InvertedSwapThresholdIndicators[i].style.height = '100%');
+		evt.target.value === 'v' && (example7InvertedSwapThresholdIndicators[i].style.width = '100%');
+	}
+
+	for (i = 0; i < example7SwapThresholdIndicators.length; i++) {
+		if (evt.target.value === 'h') {
+			example7SwapThresholdIndicators[i].style.height = '100%';
+			example7SwapThresholdIndicators[i].style.marginLeft = '50%';
+			example7SwapThresholdIndicators[i].style.transform = 'translateX(-50%)';
+
+			example7SwapThresholdIndicators[i].style.marginTop = '0';
+		} else {
+			example7SwapThresholdIndicators[i].style.width = '100%';
+			example7SwapThresholdIndicators[i].style.marginTop = '50%';
+			example7SwapThresholdIndicators[i].style.transform = 'translateY(-50%)';
+
+			example7SwapThresholdIndicators[i].style.marginLeft = '0';
+		}
+	}
+
+	if (evt.target.value === 'h') {
+		example7SizeProperty = 'width';
+		example7Sortable.option('direction', 'horizontal');
+	} else {
+		example7SizeProperty = 'height';
+		example7Sortable.option('direction', 'vertical');
+	}
+
+	renderThresholdWidth({
+		target: example7SwapThresholdInput
+	});
+}
+example7DirectionInput.addEventListener('input', renderDirection);
+
+renderDirection({
+	target: example7DirectionInput
+});
+
+
+// Grid demo
+new Sortable(gridDemo, {
+	animation: 150,
+	ghostClass: 'blue-background-class'
+});
+
+// Nested demo
+var nestedSortables = [].slice.call(document.querySelectorAll('.nested-sortable'));
+
+// Loop through each nested sortable element
+for (var i = 0; i < nestedSortables.length; i++) {
+	new Sortable(nestedSortables[i], {
+		group: 'nested',
+		animation: 150,
+		fallbackOnBody: true,
+		swapThreshold: 0.65
+	});
+}
+
+// MultiDrag demo
+new Sortable(multiDragDemo, {
+	multiDrag: true,
+	selectedClass: 'selected',
+	animation: 150
+});
+
+
+// Swap demo
+new Sortable(swapDemo, {
+	swap: true,
+	swapClass: 'highlight',
+	animation: 150
+});

+ 32 - 0
public/assets/libs/Sortable/st/iframe/frame.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="utf-8">
+</head>
+<body>
+
+<!-- Latest compiled and minified CSS -->
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
+
+
+<!-- List with handle -->
+<div id="listWithHandle" class="list-group">
+	<div class="list-group-item">
+		<span class="badge">14</span>
+		<span class="glyphicon glyphicon-move" aria-hidden="true"></span>
+		Drag me by the handle
+	</div>
+	<div class="list-group-item">
+		<span class="badge">2</span>
+		<span class="glyphicon glyphicon-move" aria-hidden="true"></span>
+		You can also select text
+	</div>
+	<div class="list-group-item">
+		<span class="badge">1</span>
+		<span class="glyphicon glyphicon-move" aria-hidden="true"></span>
+		Best of both worlds!
+	</div>
+</div>
+
+</body>
+</html>

+ 49 - 0
public/assets/libs/Sortable/st/iframe/index.html

@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+	<meta charset="utf-8">
+	<title>IFrame playground</title>
+</head>
+<body>
+
+
+<!-- Latest compiled and minified CSS -->
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css"/>
+
+
+<!-- Latest Sortable -->
+<script src="../../Sortable.js"></script>
+
+
+<!-- Simple List -->
+<div id="simpleList" class="list-group">
+	<div class="list-group-item">This is <a href="http://rubaxa.github.io/Sortable/">Sortable</a></div>
+	<div class="list-group-item">It works with Bootstrap...</div>
+	<div class="list-group-item">...out of the box.</div>
+	<div class="list-group-item">It has support for touch devices.</div>
+	<div class="list-group-item">Just drag some elements around.</div>
+</div>
+
+<script>
+	(function () {
+		Sortable.create(simpleList, {group: 'shared'});
+
+
+		var iframe = document.createElement('iframe');
+
+		iframe.src = 'frame.html';
+		iframe.width = '100%';
+		iframe.onload = function () {
+			var doc = iframe.contentDocument,
+					list = doc.getElementById('listWithHandle');
+
+			Sortable.create(list, {group: 'shared'});
+		};
+
+
+		document.body.appendChild(iframe);
+	})();
+</script>
+
+</body>
+</html>

BIN
public/assets/libs/Sortable/st/logo.png


BIN
public/assets/libs/Sortable/st/og-image.png


+ 1 - 0
public/assets/libs/Sortable/st/prettify/prettify.css

@@ -0,0 +1 @@
+.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.clo,.opn,.pun{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.kwd,.tag,.typ{font-weight:700}.str{color:#060}.kwd{color:#006}.com{color:#600;font-style:italic}.typ{color:#404}.lit{color:#044}.clo,.opn,.pun{color:#440}.tag{color:#006}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}

+ 46 - 0
public/assets/libs/Sortable/st/prettify/prettify.js

@@ -0,0 +1,46 @@
+!function(){/*
+
+ Copyright (C) 2006 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+"undefined"!==typeof window&&(window.PR_SHOULD_USE_CONTINUATION=!0);
+(function(){function T(a){function d(e){var a=e.charCodeAt(0);if(92!==a)return a;var c=e.charAt(1);return(a=w[c])?a:"0"<=c&&"7">=c?parseInt(e.substring(1),8):"u"===c||"x"===c?parseInt(e.substring(2),16):e.charCodeAt(1)}function f(e){if(32>e)return(16>e?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);return"\\"===e||"-"===e||"]"===e||"^"===e?"\\"+e:e}function c(e){var c=e.substring(1,e.length-1).match(RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));
+e=[];var a="^"===c[0],b=["["];a&&b.push("^");for(var a=a?1:0,g=c.length;a<g;++a){var h=c[a];if(/\\[bdsw]/i.test(h))b.push(h);else{var h=d(h),k;a+2<g&&"-"===c[a+1]?(k=d(c[a+2]),a+=2):k=h;e.push([h,k]);65>k||122<h||(65>k||90<h||e.push([Math.max(65,h)|32,Math.min(k,90)|32]),97>k||122<h||e.push([Math.max(97,h)&-33,Math.min(k,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});c=[];g=[];for(a=0;a<e.length;++a)h=e[a],h[0]<=g[1]+1?g[1]=Math.max(g[1],h[1]):c.push(g=h);for(a=0;a<c.length;++a)h=
+c[a],b.push(f(h[0])),h[1]>h[0]&&(h[1]+1>h[0]&&b.push("-"),b.push(f(h[1])));b.push("]");return b.join("")}function m(e){for(var a=e.source.match(RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g")),b=a.length,d=[],g=0,h=0;g<b;++g){var k=a[g];"("===k?++h:"\\"===k.charAt(0)&&(k=+k.substring(1))&&(k<=h?d[k]=-1:a[g]=f(k))}for(g=1;g<d.length;++g)-1===d[g]&&(d[g]=++E);for(h=g=0;g<b;++g)k=a[g],
+"("===k?(++h,d[h]||(a[g]="(?:")):"\\"===k.charAt(0)&&(k=+k.substring(1))&&k<=h&&(a[g]="\\"+d[k]);for(g=0;g<b;++g)"^"===a[g]&&"^"!==a[g+1]&&(a[g]="");if(e.ignoreCase&&q)for(g=0;g<b;++g)k=a[g],e=k.charAt(0),2<=k.length&&"["===e?a[g]=c(k):"\\"!==e&&(a[g]=k.replace(/[a-zA-Z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var E=0,q=!1,l=!1,n=0,b=a.length;n<b;++n){var p=a[n];if(p.ignoreCase)l=!0;else if(/[a-z]/i.test(p.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,
+""))){q=!0;l=!1;break}}for(var w={b:8,t:9,n:10,v:11,f:12,r:13},r=[],n=0,b=a.length;n<b;++n){p=a[n];if(p.global||p.multiline)throw Error(""+p);r.push("(?:"+m(p)+")")}return new RegExp(r.join("|"),l?"gi":"g")}function U(a,d){function f(a){var b=a.nodeType;if(1==b){if(!c.test(a.className)){for(b=a.firstChild;b;b=b.nextSibling)f(b);b=a.nodeName.toLowerCase();if("br"===b||"li"===b)m[l]="\n",q[l<<1]=E++,q[l++<<1|1]=a}}else if(3==b||4==b)b=a.nodeValue,b.length&&(b=d?b.replace(/\r\n?/g,"\n"):b.replace(/[ \t\r\n]+/g,
+" "),m[l]=b,q[l<<1]=E,E+=b.length,q[l++<<1|1]=a)}var c=/(?:^|\s)nocode(?:\s|$)/,m=[],E=0,q=[],l=0;f(a);return{a:m.join("").replace(/\n$/,""),c:q}}function J(a,d,f,c,m){f&&(a={h:a,l:1,j:null,m:null,a:f,c:null,i:d,g:null},c(a),m.push.apply(m,a.g))}function V(a){for(var d=void 0,f=a.firstChild;f;f=f.nextSibling)var c=f.nodeType,d=1===c?d?a:f:3===c?W.test(f.nodeValue)?a:d:d;return d===a?void 0:d}function G(a,d){function f(a){for(var l=a.i,n=a.h,b=[l,"pln"],p=0,q=a.a.match(m)||[],r={},e=0,t=q.length;e<
+t;++e){var z=q[e],v=r[z],g=void 0,h;if("string"===typeof v)h=!1;else{var k=c[z.charAt(0)];if(k)g=z.match(k[1]),v=k[0];else{for(h=0;h<E;++h)if(k=d[h],g=z.match(k[1])){v=k[0];break}g||(v="pln")}!(h=5<=v.length&&"lang-"===v.substring(0,5))||g&&"string"===typeof g[1]||(h=!1,v="src");h||(r[z]=v)}k=p;p+=z.length;if(h){h=g[1];var A=z.indexOf(h),C=A+h.length;g[2]&&(C=z.length-g[2].length,A=C-h.length);v=v.substring(5);J(n,l+k,z.substring(0,A),f,b);J(n,l+k+A,h,K(v,h),b);J(n,l+k+C,z.substring(C),f,b)}else b.push(l+
+k,v)}a.g=b}var c={},m;(function(){for(var f=a.concat(d),l=[],n={},b=0,p=f.length;b<p;++b){var w=f[b],r=w[3];if(r)for(var e=r.length;0<=--e;)c[r.charAt(e)]=w;w=w[1];r=""+w;n.hasOwnProperty(r)||(l.push(w),n[r]=null)}l.push(/[\0-\uffff]/);m=T(l)})();var E=d.length;return f}function x(a){var d=[],f=[];a.tripleQuotedStrings?d.push(["str",/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,
+null,"'\""]):a.multiLineStrings?d.push(["str",/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"]):d.push(["str",/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"]);a.verbatimStrings&&f.push(["str",/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null]);var c=a.hashComments;c&&(a.cStyleComments?(1<c?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,
+null,"#"]),f.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])):d.push(["com",/^#[^\r\n]*/,null,"#"]));a.cStyleComments&&(f.push(["com",/^\/\/[^\r\n]*/,null]),f.push(["com",/^\/\*[\s\S]*?(?:\*\/|$)/,null]));if(c=a.regexLiterals){var m=(c=1<c?"":"\n\r")?".":"[\\S\\s]";f.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+
+("/(?=[^/*"+c+"])(?:[^/\\x5B\\x5C"+c+"]|\\x5C"+m+"|\\x5B(?:[^\\x5C\\x5D"+c+"]|\\x5C"+m+")*(?:\\x5D|$))+/")+")")])}(c=a.types)&&f.push(["typ",c]);c=(""+a.keywords).replace(/^ | $/g,"");c.length&&f.push(["kwd",new RegExp("^(?:"+c.replace(/[\s,]+/g,"|")+")\\b"),null]);d.push(["pln",/^\s+/,null," \r\n\t\u00a0"]);c="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(c+="(?!s*/)");f.push(["lit",/^@[a-z_$][a-z_$@0-9]*/i,null],["typ",/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],["pln",/^[a-z_$][a-z_$@0-9]*/i,
+null],["lit",/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,null,"0123456789"],["pln",/^\\[\s\S]?/,null],["pun",new RegExp(c),null]);return G(d,f)}function L(a,d,f){function c(a){var b=a.nodeType;if(1==b&&!t.test(a.className))if("br"===a.nodeName.toLowerCase())m(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)c(a);else if((3==b||4==b)&&f){var e=a.nodeValue,d=e.match(q);d&&(b=e.substring(0,d.index),a.nodeValue=b,(e=e.substring(d.index+
+d[0].length))&&a.parentNode.insertBefore(l.createTextNode(e),a.nextSibling),m(a),b||a.parentNode.removeChild(a))}}function m(a){function c(a,b){var e=b?a.cloneNode(!1):a,k=a.parentNode;if(k){var k=c(k,1),d=a.nextSibling;k.appendChild(e);for(var f=d;f;f=d)d=f.nextSibling,k.appendChild(f)}return e}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;a=c(a.nextSibling,0);for(var e;(e=a.parentNode)&&1===e.nodeType;)a=e;b.push(a)}for(var t=/(?:^|\s)nocode(?:\s|$)/,q=/\r\n?|\n/,l=a.ownerDocument,n=l.createElement("li");a.firstChild;)n.appendChild(a.firstChild);
+for(var b=[n],p=0;p<b.length;++p)c(b[p]);d===(d|0)&&b[0].setAttribute("value",d);var w=l.createElement("ol");w.className="linenums";d=Math.max(0,d-1|0)||0;for(var p=0,r=b.length;p<r;++p)n=b[p],n.className="L"+(p+d)%10,n.firstChild||n.appendChild(l.createTextNode("\u00a0")),w.appendChild(n);a.appendChild(w)}function t(a,d){for(var f=d.length;0<=--f;){var c=d[f];I.hasOwnProperty(c)?D.console&&console.warn("cannot override language handler %s",c):I[c]=a}}function K(a,d){a&&I.hasOwnProperty(a)||(a=/^\s*</.test(d)?
+"default-markup":"default-code");return I[a]}function M(a){var d=a.j;try{var f=U(a.h,a.l),c=f.a;a.a=c;a.c=f.c;a.i=0;K(d,c)(a);var m=/\bMSIE\s(\d+)/.exec(navigator.userAgent),m=m&&8>=+m[1],d=/\n/g,t=a.a,q=t.length,f=0,l=a.c,n=l.length,c=0,b=a.g,p=b.length,w=0;b[p]=q;var r,e;for(e=r=0;e<p;)b[e]!==b[e+2]?(b[r++]=b[e++],b[r++]=b[e++]):e+=2;p=r;for(e=r=0;e<p;){for(var x=b[e],z=b[e+1],v=e+2;v+2<=p&&b[v+1]===z;)v+=2;b[r++]=x;b[r++]=z;e=v}b.length=r;var g=a.h;a="";g&&(a=g.style.display,g.style.display="none");
+try{for(;c<n;){var h=l[c+2]||q,k=b[w+2]||q,v=Math.min(h,k),A=l[c+1],C;if(1!==A.nodeType&&(C=t.substring(f,v))){m&&(C=C.replace(d,"\r"));A.nodeValue=C;var N=A.ownerDocument,u=N.createElement("span");u.className=b[w+1];var B=A.parentNode;B.replaceChild(u,A);u.appendChild(A);f<h&&(l[c+1]=A=N.createTextNode(t.substring(v,h)),B.insertBefore(A,u.nextSibling))}f=v;f>=h&&(c+=2);f>=k&&(w+=2)}}finally{g&&(g.style.display=a)}}catch(y){D.console&&console.log(y&&y.stack||y)}}var D="undefined"!==typeof window?
+window:{},B=["break,continue,do,else,for,if,return,while"],F=[[B,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],H=[F,"alignas,alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],
+O=[F,"abstract,assert,boolean,byte,extends,finally,final,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],P=[F,"abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface,internal,into,is,join,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,value,var,virtual,where,yield"],
+F=[F,"abstract,async,await,constructor,debugger,enum,eval,export,from,function,get,import,implements,instanceof,interface,let,null,of,set,undefined,var,with,yield,Infinity,NaN"],Q=[B,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],R=[B,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],
+B=[B,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],S=/^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,W=/\S/,X=x({keywords:[H,P,O,F,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",Q,R,B],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),
+I={};t(X,["default-code"]);t(G([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));t(G([["pln",/^[\s]+/,
+null," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],["pun",/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);
+t(G([],[["atv",/^[\s\S]+/]]),["uq.val"]);t(x({keywords:H,hashComments:!0,cStyleComments:!0,types:S}),"c cc cpp cxx cyc m".split(" "));t(x({keywords:"null,true,false"}),["json"]);t(x({keywords:P,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:S}),["cs"]);t(x({keywords:O,cStyleComments:!0}),["java"]);t(x({keywords:B,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);t(x({keywords:Q,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);t(x({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",
+hashComments:!0,multiLineStrings:!0,regexLiterals:2}),["perl","pl","pm"]);t(x({keywords:R,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);t(x({keywords:F,cStyleComments:!0,regexLiterals:!0}),["javascript","js","ts","typescript"]);t(x({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,
+regexLiterals:!0}),["coffee"]);t(G([],[["str",/^[\s\S]+/]]),["regex"]);var Y=D.PR={createSimpleLexer:G,registerLangHandler:t,sourceDecorator:x,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:D.prettyPrintOne=function(a,d,f){f=f||!1;d=d||null;var c=document.createElement("div");c.innerHTML="<pre>"+a+"</pre>";
+c=c.firstChild;f&&L(c,f,!0);M({j:d,m:f,h:c,l:1,a:null,i:null,c:null,g:null});return c.innerHTML},prettyPrint:D.prettyPrint=function(a,d){function f(){for(var c=D.PR_SHOULD_USE_CONTINUATION?b.now()+250:Infinity;p<x.length&&b.now()<c;p++){for(var d=x[p],l=g,n=d;n=n.previousSibling;){var m=n.nodeType,u=(7===m||8===m)&&n.nodeValue;if(u?!/^\??prettify\b/.test(u):3!==m||/\S/.test(n.nodeValue))break;if(u){l={};u.replace(/\b(\w+)=([\w:.%+-]+)/g,function(a,b,c){l[b]=c});break}}n=d.className;if((l!==g||r.test(n))&&
+!e.test(n)){m=!1;for(u=d.parentNode;u;u=u.parentNode)if(v.test(u.tagName)&&u.className&&r.test(u.className)){m=!0;break}if(!m){d.className+=" prettyprinted";m=l.lang;if(!m){var m=n.match(w),q;!m&&(q=V(d))&&z.test(q.tagName)&&(m=q.className.match(w));m&&(m=m[1])}if(B.test(d.tagName))u=1;else var u=d.currentStyle,y=t.defaultView,u=(u=u?u.whiteSpace:y&&y.getComputedStyle?y.getComputedStyle(d,null).getPropertyValue("white-space"):0)&&"pre"===u.substring(0,3);y=l.linenums;(y="true"===y||+y)||(y=(y=n.match(/\blinenums\b(?::(\d+))?/))?
+y[1]&&y[1].length?+y[1]:!0:!1);y&&L(d,y,u);M({j:m,h:d,m:y,l:u,a:null,i:null,c:null,g:null})}}}p<x.length?D.setTimeout(f,250):"function"===typeof a&&a()}for(var c=d||document.body,t=c.ownerDocument||document,c=[c.getElementsByTagName("pre"),c.getElementsByTagName("code"),c.getElementsByTagName("xmp")],x=[],q=0;q<c.length;++q)for(var l=0,n=c[q].length;l<n;++l)x.push(c[q][l]);var c=null,b=Date;b.now||(b={now:function(){return+new Date}});var p=0,w=/\blang(?:uage)?-([\w.]+)(?!\S)/,r=/\bprettyprint\b/,
+e=/\bprettyprinted\b/,B=/pre|xmp/i,z=/^code$/i,v=/^(?:pre|code|xmp)$/i,g={};f()}},H=D.define;"function"===typeof H&&H.amd&&H("google-code-prettify",[],function(){return Y})})();}()

+ 64 - 0
public/assets/libs/Sortable/st/prettify/run_prettify.js

@@ -0,0 +1,64 @@
+!function(){/*
+
+ Copyright (C) 2013 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ Copyright (C) 2006 Google Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+(function(){function aa(g){function r(){try{L.doScroll("left")}catch(ba){k.setTimeout(r,50);return}x("poll")}function x(r){if("readystatechange"!=r.type||"complete"==z.readyState)("load"==r.type?k:z)[B](n+r.type,x,!1),!l&&(l=!0)&&g.call(k,r.type||r)}var X=z.addEventListener,l=!1,E=!0,v=X?"addEventListener":"attachEvent",B=X?"removeEventListener":"detachEvent",n=X?"":"on";if("complete"==z.readyState)g.call(k,"lazy");else{if(z.createEventObject&&L.doScroll){try{E=!k.frameElement}catch(ba){}E&&r()}z[v](n+
+"DOMContentLoaded",x,!1);z[v](n+"readystatechange",x,!1);k[v](n+"load",x,!1)}}function T(){U&&aa(function(){var g=M.length;ca(g?function(){for(var r=0;r<g;++r)(function(g){k.setTimeout(function(){k.exports[M[g]].apply(k,arguments)},0)})(r)}:void 0)})}for(var k=window,z=document,L=z.documentElement,N=z.head||z.getElementsByTagName("head")[0]||L,B="",F=z.getElementsByTagName("script"),l=F.length;0<=--l;){var O=F[l],Y=O.src.match(/^[^?#]*\/run_prettify\.js(\?[^#]*)?(?:#.*)?$/);if(Y){B=Y[1]||"";O.parentNode.removeChild(O);
+break}}var U=!0,H=[],P=[],M=[];B.replace(/[?&]([^&=]+)=([^&]+)/g,function(g,r,x){x=decodeURIComponent(x);r=decodeURIComponent(r);"autorun"==r?U=!/^[0fn]/i.test(x):"lang"==r?H.push(x):"skin"==r?P.push(x):"callback"==r&&M.push(x)});l=0;for(B=H.length;l<B;++l)(function(){var g=z.createElement("script");g.onload=g.onerror=g.onreadystatechange=function(){!g||g.readyState&&!/loaded|complete/.test(g.readyState)||(g.onerror=g.onload=g.onreadystatechange=null,--S,S||k.setTimeout(T,0),g.parentNode&&g.parentNode.removeChild(g),
+g=null)};g.type="text/javascript";g.src="https://cdn.rawgit.com/google/code-prettify/master/loader/lang-"+encodeURIComponent(H[l])+".js";N.insertBefore(g,N.firstChild)})(H[l]);for(var S=H.length,F=[],l=0,B=P.length;l<B;++l)F.push("https://cdn.rawgit.com/google/code-prettify/master/loader/skins/"+encodeURIComponent(P[l])+".css");F.push("https://cdn.rawgit.com/google/code-prettify/master/loader/prettify.css");(function(g){function r(l){if(l!==x){var k=z.createElement("link");k.rel="stylesheet";k.type=
+"text/css";l+1<x&&(k.error=k.onerror=function(){r(l+1)});k.href=g[l];N.appendChild(k)}}var x=g.length;r(0)})(F);var ca=function(){"undefined"!==typeof window&&(window.PR_SHOULD_USE_CONTINUATION=!0);var g;(function(){function r(a){function d(e){var a=e.charCodeAt(0);if(92!==a)return a;var c=e.charAt(1);return(a=k[c])?a:"0"<=c&&"7">=c?parseInt(e.substring(1),8):"u"===c||"x"===c?parseInt(e.substring(2),16):e.charCodeAt(1)}function f(e){if(32>e)return(16>e?"\\x0":"\\x")+e.toString(16);e=String.fromCharCode(e);
+return"\\"===e||"-"===e||"]"===e||"^"===e?"\\"+e:e}function c(e){var c=e.substring(1,e.length-1).match(RegExp("\\\\u[0-9A-Fa-f]{4}|\\\\x[0-9A-Fa-f]{2}|\\\\[0-3][0-7]{0,2}|\\\\[0-7]{1,2}|\\\\[\\s\\S]|-|[^-\\\\]","g"));e=[];var a="^"===c[0],b=["["];a&&b.push("^");for(var a=a?1:0,h=c.length;a<h;++a){var m=c[a];if(/\\[bdsw]/i.test(m))b.push(m);else{var m=d(m),p;a+2<h&&"-"===c[a+1]?(p=d(c[a+2]),a+=2):p=m;e.push([m,p]);65>p||122<m||(65>p||90<m||e.push([Math.max(65,m)|32,Math.min(p,90)|32]),97>p||122<m||
+e.push([Math.max(97,m)&-33,Math.min(p,122)&-33]))}}e.sort(function(e,a){return e[0]-a[0]||a[1]-e[1]});c=[];h=[];for(a=0;a<e.length;++a)m=e[a],m[0]<=h[1]+1?h[1]=Math.max(h[1],m[1]):c.push(h=m);for(a=0;a<c.length;++a)m=c[a],b.push(f(m[0])),m[1]>m[0]&&(m[1]+1>m[0]&&b.push("-"),b.push(f(m[1])));b.push("]");return b.join("")}function g(e){for(var a=e.source.match(RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)",
+"g")),b=a.length,d=[],h=0,m=0;h<b;++h){var p=a[h];"("===p?++m:"\\"===p.charAt(0)&&(p=+p.substring(1))&&(p<=m?d[p]=-1:a[h]=f(p))}for(h=1;h<d.length;++h)-1===d[h]&&(d[h]=++r);for(m=h=0;h<b;++h)p=a[h],"("===p?(++m,d[m]||(a[h]="(?:")):"\\"===p.charAt(0)&&(p=+p.substring(1))&&p<=m&&(a[h]="\\"+d[p]);for(h=0;h<b;++h)"^"===a[h]&&"^"!==a[h+1]&&(a[h]="");if(e.ignoreCase&&A)for(h=0;h<b;++h)p=a[h],e=p.charAt(0),2<=p.length&&"["===e?a[h]=c(p):"\\"!==e&&(a[h]=p.replace(/[a-zA-Z]/g,function(a){a=a.charCodeAt(0);
+return"["+String.fromCharCode(a&-33,a|32)+"]"}));return a.join("")}for(var r=0,A=!1,q=!1,I=0,b=a.length;I<b;++I){var t=a[I];if(t.ignoreCase)q=!0;else if(/[a-z]/i.test(t.source.replace(/\\u[0-9a-f]{4}|\\x[0-9a-f]{2}|\\[^ux]/gi,""))){A=!0;q=!1;break}}for(var k={b:8,t:9,n:10,v:11,f:12,r:13},u=[],I=0,b=a.length;I<b;++I){t=a[I];if(t.global||t.multiline)throw Error(""+t);u.push("(?:"+g(t)+")")}return new RegExp(u.join("|"),q?"gi":"g")}function l(a,d){function f(a){var b=a.nodeType;if(1==b){if(!c.test(a.className)){for(b=
+a.firstChild;b;b=b.nextSibling)f(b);b=a.nodeName.toLowerCase();if("br"===b||"li"===b)g[q]="\n",A[q<<1]=r++,A[q++<<1|1]=a}}else if(3==b||4==b)b=a.nodeValue,b.length&&(b=d?b.replace(/\r\n?/g,"\n"):b.replace(/[ \t\r\n]+/g," "),g[q]=b,A[q<<1]=r,r+=b.length,A[q++<<1|1]=a)}var c=/(?:^|\s)nocode(?:\s|$)/,g=[],r=0,A=[],q=0;f(a);return{a:g.join("").replace(/\n$/,""),c:A}}function k(a,d,f,c,g){f&&(a={h:a,l:1,j:null,m:null,a:f,c:null,i:d,g:null},c(a),g.push.apply(g,a.g))}function z(a){for(var d=void 0,f=a.firstChild;f;f=
+f.nextSibling)var c=f.nodeType,d=1===c?d?a:f:3===c?S.test(f.nodeValue)?a:d:d;return d===a?void 0:d}function E(a,d){function f(a){for(var q=a.i,r=a.h,b=[q,"pln"],t=0,A=a.a.match(g)||[],u={},e=0,l=A.length;e<l;++e){var D=A[e],w=u[D],h=void 0,m;if("string"===typeof w)m=!1;else{var p=c[D.charAt(0)];if(p)h=D.match(p[1]),w=p[0];else{for(m=0;m<n;++m)if(p=d[m],h=D.match(p[1])){w=p[0];break}h||(w="pln")}!(m=5<=w.length&&"lang-"===w.substring(0,5))||h&&"string"===typeof h[1]||(m=!1,w="src");m||(u[D]=w)}p=t;
+t+=D.length;if(m){m=h[1];var C=D.indexOf(m),G=C+m.length;h[2]&&(G=D.length-h[2].length,C=G-m.length);w=w.substring(5);k(r,q+p,D.substring(0,C),f,b);k(r,q+p+C,m,F(w,m),b);k(r,q+p+G,D.substring(G),f,b)}else b.push(q+p,w)}a.g=b}var c={},g;(function(){for(var f=a.concat(d),q=[],k={},b=0,t=f.length;b<t;++b){var n=f[b],u=n[3];if(u)for(var e=u.length;0<=--e;)c[u.charAt(e)]=n;n=n[1];u=""+n;k.hasOwnProperty(u)||(q.push(n),k[u]=null)}q.push(/[\0-\uffff]/);g=r(q)})();var n=d.length;return f}function v(a){var d=
+[],f=[];a.tripleQuotedStrings?d.push(["str",/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""]):a.multiLineStrings?d.push(["str",/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"]):d.push(["str",/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"]);a.verbatimStrings&&
+f.push(["str",/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null]);var c=a.hashComments;c&&(a.cStyleComments?(1<c?d.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"]):d.push(["com",/^#(?:(?:define|e(?:l|nd)if|else|error|ifn?def|include|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"]),f.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h(?:h|pp|\+\+)?|[a-z]\w*)>/,null])):d.push(["com",/^#[^\r\n]*/,null,"#"]));a.cStyleComments&&(f.push(["com",/^\/\/[^\r\n]*/,null]),f.push(["com",/^\/\*[\s\S]*?(?:\*\/|$)/,
+null]));if(c=a.regexLiterals){var g=(c=1<c?"":"\n\r")?".":"[\\S\\s]";f.push(["lang-regex",RegExp("^(?:^^\\.?|[+-]|[!=]=?=?|\\#|%=?|&&?=?|\\(|\\*=?|[+\\-]=|->|\\/=?|::?|<<?=?|>>?>?=?|,|;|\\?|@|\\[|~|{|\\^\\^?=?|\\|\\|?=?|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*("+("/(?=[^/*"+c+"])(?:[^/\\x5B\\x5C"+c+"]|\\x5C"+g+"|\\x5B(?:[^\\x5C\\x5D"+c+"]|\\x5C"+g+")*(?:\\x5D|$))+/")+")")])}(c=a.types)&&f.push(["typ",c]);c=(""+a.keywords).replace(/^ | $/g,"");c.length&&f.push(["kwd",
+new RegExp("^(?:"+c.replace(/[\s,]+/g,"|")+")\\b"),null]);d.push(["pln",/^\s+/,null," \r\n\t\u00a0"]);c="^.[^\\s\\w.$@'\"`/\\\\]*";a.regexLiterals&&(c+="(?!s*/)");f.push(["lit",/^@[a-z_$][a-z_$@0-9]*/i,null],["typ",/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],["pln",/^[a-z_$][a-z_$@0-9]*/i,null],["lit",/^(?:0x[a-f0-9]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+\-]?\d+)?)[a-z]*/i,null,"0123456789"],["pln",/^\\[\s\S]?/,null],["pun",new RegExp(c),null]);return E(d,f)}function B(a,d,f){function c(a){var b=
+a.nodeType;if(1==b&&!r.test(a.className))if("br"===a.nodeName.toLowerCase())g(a),a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)c(a);else if((3==b||4==b)&&f){var e=a.nodeValue,d=e.match(n);d&&(b=e.substring(0,d.index),a.nodeValue=b,(e=e.substring(d.index+d[0].length))&&a.parentNode.insertBefore(q.createTextNode(e),a.nextSibling),g(a),b||a.parentNode.removeChild(a))}}function g(a){function c(a,b){var e=b?a.cloneNode(!1):a,p=a.parentNode;if(p){var p=c(p,1),d=a.nextSibling;
+p.appendChild(e);for(var f=d;f;f=d)d=f.nextSibling,p.appendChild(f)}return e}for(;!a.nextSibling;)if(a=a.parentNode,!a)return;a=c(a.nextSibling,0);for(var e;(e=a.parentNode)&&1===e.nodeType;)a=e;b.push(a)}for(var r=/(?:^|\s)nocode(?:\s|$)/,n=/\r\n?|\n/,q=a.ownerDocument,k=q.createElement("li");a.firstChild;)k.appendChild(a.firstChild);for(var b=[k],t=0;t<b.length;++t)c(b[t]);d===(d|0)&&b[0].setAttribute("value",d);var l=q.createElement("ol");l.className="linenums";d=Math.max(0,d-1|0)||0;for(var t=
+0,u=b.length;t<u;++t)k=b[t],k.className="L"+(t+d)%10,k.firstChild||k.appendChild(q.createTextNode("\u00a0")),l.appendChild(k);a.appendChild(l)}function n(a,d){for(var f=d.length;0<=--f;){var c=d[f];V.hasOwnProperty(c)?Q.console&&console.warn("cannot override language handler %s",c):V[c]=a}}function F(a,d){a&&V.hasOwnProperty(a)||(a=/^\s*</.test(d)?"default-markup":"default-code");return V[a]}function H(a){var d=a.j;try{var f=l(a.h,a.l),c=f.a;a.a=c;a.c=f.c;a.i=0;F(d,c)(a);var g=/\bMSIE\s(\d+)/.exec(navigator.userAgent),
+g=g&&8>=+g[1],d=/\n/g,r=a.a,k=r.length,f=0,q=a.c,n=q.length,c=0,b=a.g,t=b.length,v=0;b[t]=k;var u,e;for(e=u=0;e<t;)b[e]!==b[e+2]?(b[u++]=b[e++],b[u++]=b[e++]):e+=2;t=u;for(e=u=0;e<t;){for(var x=b[e],z=b[e+1],w=e+2;w+2<=t&&b[w+1]===z;)w+=2;b[u++]=x;b[u++]=z;e=w}b.length=u;var h=a.h;a="";h&&(a=h.style.display,h.style.display="none");try{for(;c<n;){var m=q[c+2]||k,p=b[v+2]||k,w=Math.min(m,p),C=q[c+1],G;if(1!==C.nodeType&&(G=r.substring(f,w))){g&&(G=G.replace(d,"\r"));C.nodeValue=G;var Z=C.ownerDocument,
+W=Z.createElement("span");W.className=b[v+1];var B=C.parentNode;B.replaceChild(W,C);W.appendChild(C);f<m&&(q[c+1]=C=Z.createTextNode(r.substring(w,m)),B.insertBefore(C,W.nextSibling))}f=w;f>=m&&(c+=2);f>=p&&(v+=2)}}finally{h&&(h.style.display=a)}}catch(y){Q.console&&console.log(y&&y.stack||y)}}var Q="undefined"!==typeof window?window:{},J=["break,continue,do,else,for,if,return,while"],K=[[J,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,restrict,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
+"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],R=[K,"alignas,alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,noexcept,noreturn,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],L=[K,"abstract,assert,boolean,byte,extends,finally,final,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
+M=[K,"abstract,add,alias,as,ascending,async,await,base,bool,by,byte,checked,decimal,delegate,descending,dynamic,event,finally,fixed,foreach,from,get,global,group,implicit,in,interface,internal,into,is,join,let,lock,null,object,out,override,orderby,params,partial,readonly,ref,remove,sbyte,sealed,select,set,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,value,var,virtual,where,yield"],K=[K,"abstract,async,await,constructor,debugger,enum,eval,export,from,function,get,import,implements,instanceof,interface,let,null,of,set,undefined,var,with,yield,Infinity,NaN"],
+N=[J,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],O=[J,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],J=[J,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],P=/^(DIR|FILE|array|vector|(de|priority_)?queue|(forward_)?list|stack|(const_)?(reverse_)?iterator|(unordered_)?(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
+S=/\S/,T=v({keywords:[R,M,L,K,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",N,O,J],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),V={};n(T,["default-code"]);n(E([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
+/^<xmp\b[^>]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),"default-markup htm html mxml xhtml xml xsl".split(" "));n(E([["pln",/^[\s]+/,null," \t\r\n"],["atv",/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],
+["pun",/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);n(E([],[["atv",/^[\s\S]+/]]),["uq.val"]);n(v({keywords:R,hashComments:!0,cStyleComments:!0,types:P}),"c cc cpp cxx cyc m".split(" "));n(v({keywords:"null,true,false"}),["json"]);n(v({keywords:M,hashComments:!0,cStyleComments:!0,
+verbatimStrings:!0,types:P}),["cs"]);n(v({keywords:L,cStyleComments:!0}),["java"]);n(v({keywords:J,hashComments:!0,multiLineStrings:!0}),["bash","bsh","csh","sh"]);n(v({keywords:N,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),["cv","py","python"]);n(v({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:2}),
+["perl","pl","pm"]);n(v({keywords:O,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb","ruby"]);n(v({keywords:K,cStyleComments:!0,regexLiterals:!0}),["javascript","js","ts","typescript"]);n(v({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,throw,true,try,unless,until,when,while,yes",hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);n(E([],[["str",/^[\s\S]+/]]),
+["regex"]);var U=Q.PR={createSimpleLexer:E,registerLangHandler:n,sourceDecorator:v,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ",prettyPrintOne:function(a,d,f){f=f||!1;d=d||null;var c=document.createElement("div");c.innerHTML="<pre>"+a+"</pre>";c=c.firstChild;f&&B(c,f,!0);H({j:d,m:f,h:c,l:1,a:null,i:null,c:null,g:null});
+return c.innerHTML},prettyPrint:g=function(a,d){function f(){for(var c=Q.PR_SHOULD_USE_CONTINUATION?b.now()+250:Infinity;t<r.length&&b.now()<c;t++){for(var d=r[t],k=h,n=d;n=n.previousSibling;){var q=n.nodeType,l=(7===q||8===q)&&n.nodeValue;if(l?!/^\??prettify\b/.test(l):3!==q||/\S/.test(n.nodeValue))break;if(l){k={};l.replace(/\b(\w+)=([\w:.%+-]+)/g,function(a,b,c){k[b]=c});break}}n=d.className;if((k!==h||u.test(n))&&!e.test(n)){q=!1;for(l=d.parentNode;l;l=l.parentNode)if(w.test(l.tagName)&&l.className&&
+u.test(l.className)){q=!0;break}if(!q){d.className+=" prettyprinted";q=k.lang;if(!q){var q=n.match(v),A;!q&&(A=z(d))&&D.test(A.tagName)&&(q=A.className.match(v));q&&(q=q[1])}if(x.test(d.tagName))l=1;else var l=d.currentStyle,y=g.defaultView,l=(l=l?l.whiteSpace:y&&y.getComputedStyle?y.getComputedStyle(d,null).getPropertyValue("white-space"):0)&&"pre"===l.substring(0,3);y=k.linenums;(y="true"===y||+y)||(y=(y=n.match(/\blinenums\b(?::(\d+))?/))?y[1]&&y[1].length?+y[1]:!0:!1);y&&B(d,y,l);H({j:q,h:d,m:y,
+l:l,a:null,i:null,c:null,g:null})}}}t<r.length?Q.setTimeout(f,250):"function"===typeof a&&a()}for(var c=d||document.body,g=c.ownerDocument||document,c=[c.getElementsByTagName("pre"),c.getElementsByTagName("code"),c.getElementsByTagName("xmp")],r=[],k=0;k<c.length;++k)for(var n=0,l=c[k].length;n<l;++n)r.push(c[k][n]);var c=null,b=Date;b.now||(b={now:function(){return+new Date}});var t=0,v=/\blang(?:uage)?-([\w.]+)(?!\S)/,u=/\bprettyprint\b/,e=/\bprettyprinted\b/,x=/pre|xmp/i,D=/^code$/i,w=/^(?:pre|code|xmp)$/i,
+h={};f()}},R=Q.define;"function"===typeof R&&R.amd&&R("google-code-prettify",[],function(){return U})})();return g}();S||k.setTimeout(T,0)})();}()

File diff suppressed because it is too large
+ 0 - 0
public/assets/libs/Sortable/st/saucelabs.svg


+ 254 - 0
public/assets/libs/Sortable/st/theme.css

@@ -0,0 +1,254 @@
+body {
+	font-family: Helvetica Neue, Helvetica, Arial;
+	background: rgb(244,215,201); /* Old browsers */
+	background: -moz-linear-gradient(top, rgb(244,215,201) 0%, rgb(244,226,201) 100%); /* FF3.6-15 */
+	background: -webkit-linear-gradient(top, rgb(244,215,201) 0%,rgb(244,226,201) 100%); /* Chrome10-25,Safari5.1-6 */
+	background: linear-gradient(to bottom, rgb(244,215,201) 0%,rgb(244,226,201) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
+	margin-bottom: 100px;
+}
+
+.header {
+	margin-top: 30px;
+}
+
+.header h1 {
+	margin-top: 10px;
+}
+
+h4 {
+	padding-bottom: 10px;
+}
+
+.prettyprinted {
+	margin-top: 5px;
+	border-top: none !important;
+	border-bottom: none !important;
+	border-right: none !important;
+	border-left: 1px solid rgba(0,0,0,.1) !important;
+	padding-left: 15px !important;
+	word-wrap: break-word !important;
+	overflow: default !important;
+	text-overflow: default !important;
+}
+
+.tinted {
+	background-color: #fff6b2;
+}
+
+.handle {
+	cursor: grab;
+}
+
+code {
+	color: #606;
+}
+
+.toc {
+	background-color: rgb(255,255,255,0.5);
+	border: solid #444 1px;
+	padding: 20px;
+	margin-left: auto;
+	margin-right: auto;
+	list-style: none;
+}
+
+.toc h5 {
+	margin-top: 8px;
+}
+
+.list-group-item:hover {
+	z-index: 0;
+}
+
+.input-section {
+	background-color: rgb(255,255,255,0.5);
+	padding: 20px;
+}
+
+.square-section {
+	background-color: rgb(255,255,255,0.5);
+}
+
+
+.square {
+	width: 20vw;
+	height: 20vw;
+	background-color: #00a2ff;
+	margin-top: 2vw;
+	margin-left: 2vw;
+	display: inline-block;
+	position: relative;
+}
+
+.swap-threshold-indicator {
+	background-color: #0079bf;
+	height: 100%;
+	display: inline-block;
+}
+
+.inverted-swap-threshold-indicator {
+	background-color: #0079bf;
+	height: 100%;
+	position: absolute;
+}
+
+.indicator-left {
+	left: 0;
+	top: 0;
+}
+
+.indicator-right {
+	right: 0;
+	bottom: 0;
+}
+
+.num-indicator {
+	position: absolute;
+	font-size: 50px;
+	width: 25px;
+	top: 50%;
+	left: 50%;
+    transform: translate(-50%, -50%);
+	color: white;
+}
+
+.grid-square {
+	width: 100px;
+	height: 100px;
+	display: inline-block;
+	background-color: #fff;
+	border: solid 1px rgb(0,0,0,0.2);
+	padding: 10px;
+	margin: 12px;
+}
+
+.nested-sortable, .nested-1, .nested-2, .nested-3 {
+	margin-top: 5px;
+}
+
+.nested-1 {
+	background-color: #e6e6e6;
+}
+
+.nested-2 {
+	background-color: #cccccc;
+}
+
+.nested-3 {
+	background-color: #b3b3b3;
+}
+
+.frameworks {
+	background-color: rgb(255,255,255,0.5);
+	border: solid rgb(0,0,0,0.3) 1px;
+	padding: 20px;
+}
+
+.frameworks h3 {
+	margin-top: 5px;
+}
+
+input[type=range] {
+  -webkit-appearance: none;
+  width: 100%;
+  margin: 3.8px 0;
+}
+input[type=range]:focus {
+  outline: none;
+}
+input[type=range]::-webkit-slider-runnable-track {
+  width: 100%;
+  height: 8.4px;
+  cursor: pointer;
+  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
+  background: rgba(48, 113, 169, 0);
+  border-radius: 1.3px;
+  border: 0.2px solid #010101;
+}
+input[type=range]::-webkit-slider-thumb {
+  box-shadow: 0px 0px 0.9px #000000, 0px 0px 0px #0d0d0d;
+  border: 1.3px solid rgba(0, 0, 0, 0.7);
+  height: 16px;
+  width: 16px;
+  border-radius: 49px;
+  background: #ffffff;
+  cursor: pointer;
+  -webkit-appearance: none;
+  margin-top: -4px;
+}
+input[type=range]:focus::-webkit-slider-runnable-track {
+  background: rgba(54, 126, 189, 0);
+}
+input[type=range]::-moz-range-track {
+  width: 100%;
+  height: 8.4px;
+  cursor: pointer;
+  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
+  background: rgba(48, 113, 169, 0);
+  border-radius: 1.3px;
+  border: 0.2px solid #010101;
+}
+input[type=range]::-moz-range-thumb {
+  box-shadow: 0px 0px 0.9px #000000, 0px 0px 0px #0d0d0d;
+  border: 1.3px solid rgba(0, 0, 0, 0.7);
+  height: 16px;
+  width: 16px;
+  border-radius: 49px;
+  background: #ffffff;
+  cursor: pointer;
+}
+input[type=range]::-ms-track {
+  width: 100%;
+  height: 8.4px;
+  cursor: pointer;
+  background: transparent;
+  border-color: transparent;
+  color: transparent;
+}
+input[type=range]::-ms-fill-lower {
+  background: rgba(42, 100, 149, 0);
+  border: 0.2px solid #010101;
+  border-radius: 2.6px;
+  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
+}
+input[type=range]::-ms-fill-upper {
+  background: rgba(48, 113, 169, 0);
+  border: 0.2px solid #010101;
+  border-radius: 2.6px;
+  box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d;
+}
+input[type=range]::-ms-thumb {
+  box-shadow: 0px 0px 0.9px #000000, 0px 0px 0px #0d0d0d;
+  border: 1.3px solid rgba(0, 0, 0, 0.7);
+  height: 16px;
+  width: 16px;
+  border-radius: 49px;
+  background: #ffffff;
+  cursor: pointer;
+  height: 8.4px;
+}
+input[type=range]:focus::-ms-fill-lower {
+  background: rgba(48, 113, 169, 0);
+}
+input[type=range]:focus::-ms-fill-upper {
+  background: rgba(54, 126, 189, 0);
+}
+
+.blue-background-class {
+	background-color: #C8EBFB;
+}
+
+.col {
+	padding-right: 0;
+	margin-right: 15px;
+}
+
+.selected {
+	background-color: #f9c7c8;
+	border: solid red 1px !important;
+	z-index: 1 !important;
+}
+
+.highlight {
+	background-color: #B7F8C7;
+}

+ 14 - 0
public/assets/libs/art-template/.bower.json

@@ -0,0 +1,14 @@
+{
+  "name": "art-template",
+  "homepage": "https://github.com/aui/artTemplate",
+  "version": "3.1.3",
+  "_release": "3.1.3",
+  "_resolution": {
+    "type": "version",
+    "tag": "v3.1.3",
+    "commit": "b1085f546f6d3abbf74d10a5f69d24a63e932e86"
+  },
+  "_source": "https://github.com/aui/artTemplate.git",
+  "_target": "~3.1.3",
+  "_originalSource": "art-template"
+}

+ 4 - 0
public/assets/libs/art-template/.gitignore

@@ -0,0 +1,4 @@
+.DS_Store
+node_modules
+.vscode
+coverage

+ 3 - 0
public/assets/libs/art-template/.npmignore

@@ -0,0 +1,3 @@
+test
+demo
+doc

+ 99 - 0
public/assets/libs/art-template/Gruntfile.js

@@ -0,0 +1,99 @@
+module.exports = function (grunt) {
+
+    var sources_native = [
+        'src/intro.js',
+        'src/template.js',
+        'src/config.js',
+        'src/cache.js',
+        'src/render.js',
+        'src/renderFile.js',
+        'src/get.js',
+        'src/utils.js',
+        'src/helper.js',
+        'src/onerror.js',
+        'src/compile.js',
+                    //<<<< 'src/syntax.js',
+        'src/outro.js'
+    ];
+
+    var sources_simple = Array.apply(null, sources_native);
+    sources_simple.splice(sources_native.length - 1, 0, 'src/syntax.js');
+
+
+    grunt.initConfig({
+        pkg: grunt.file.readJSON('package.json'),
+        meta: {
+            banner: '/*!<%= pkg.name %> - Template Engine | <%= pkg.homepage %>*/\n'
+        },
+        concat: {
+            options: {
+                separator: ''
+            },
+
+            'native': {
+                src: sources_native,
+                dest: 'dist/template-native-debug.js'
+            },
+
+            simple: {
+                src: sources_simple,
+                dest: 'dist/template-debug.js'
+            }
+        },
+        uglify: {
+            options: {
+                banner: '<%= meta.banner %>'
+            },
+            'native': {
+                src: '<%= concat.native.dest %>',
+                dest: 'dist/template-native.js'
+            },
+            simple: {
+                src: '<%= concat.simple.dest %>',
+                dest: 'dist/template.js'
+            }
+        },
+        qunit: {
+            files: ['test/**/*.html']
+        },
+        jshint: {
+            files: [
+              'dist/template-native.js',
+              'dist/template.js'
+            ],
+            options: {
+                curly: true,
+                eqeqeq: true,
+                immed: true,
+                latedef: true,
+                newcap: true,
+                noarg: true,
+                sub: true,
+                undef: true,
+                boss: true,
+                eqnull: true,
+                browser: true
+            },
+            globals: {
+                console: true,
+                define: true,
+                global: true,
+                module: true
+            }
+        },
+        watch: {
+            files: '<config:lint.files>',
+            tasks: 'lint qunit'
+        }
+    });
+
+    grunt.loadNpmTasks('grunt-contrib-uglify');
+    grunt.loadNpmTasks('grunt-contrib-jshint');
+    //grunt.loadNpmTasks('grunt-contrib-qunit');
+    //grunt.loadNpmTasks('grunt-contrib-watch');
+    grunt.loadNpmTasks('grunt-contrib-concat');
+
+
+    grunt.registerTask('default', ['concat', /*'jshint',*/ 'uglify']);
+
+};

+ 303 - 0
public/assets/libs/art-template/README.md

@@ -0,0 +1,303 @@
+# artTemplate-3.0
+
+新一代 javascript 模板引擎
+
+> 后会无期。2016-12-22
+
+##      	目录
+
+*	[特性](#特性)
+*	[快速上手](#快速上手)
+*	[模板语法](#模板语法)
+*	[下载](#下载)
+*	[方法](#方法)
+*	[NodeJS](#nodejs)
+*	[使用预编译](#使用预编译)
+*	[更新日志](#更新日志)
+*	[授权协议](#授权协议)
+
+##	特性
+
+1.	性能卓越,执行速度通常是 Mustache 与 tmpl 的 20 多倍([性能测试](http://aui.github.com/artTemplate/test/test-speed.html))
+2.	支持运行时调试,可精确定位异常模板所在语句([演示](http://aui.github.io/artTemplate/demo/debug.html))
+3.	对 NodeJS Express 友好支持
+4.	安全,默认对输出进行转义、在沙箱中运行编译后的代码(Node版本可以安全执行用户上传的模板)
+5.	支持``include``语句
+6.	可在浏览器端实现按路径加载模板([详情](#使用预编译))
+7.	支持预编译,可将模板转换成为非常精简的 js 文件
+8.	模板语句简洁,无需前缀引用数据,有简洁版本与原生语法版本可选
+9.	支持所有流行的浏览器
+
+## 快速上手
+
+### 编写模板
+
+使用一个``type="text/html"``的``script``标签存放模板:
+	
+	<script id="test" type="text/html">
+	<h1>{{title}}</h1>
+	<ul>
+	    {{each list as value i}}
+	        <li>索引 {{i + 1}} :{{value}}</li>
+	    {{/each}}
+	</ul>
+	</script>
+
+### 渲染模板
+	
+	var data = {
+		title: '标签',
+		list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
+	};
+	var html = template('test', data);
+	document.getElementById('content').innerHTML = html;
+
+
+[演示](http://aui.github.com/artTemplate/demo/basic.html)
+
+##	模板语法
+
+有两个版本的模板语法可以选择。
+
+###	简洁语法
+
+推荐使用,语法简单实用,利于读写。
+
+	{{if admin}}
+		{{include 'admin_content'}}
+		
+		{{each list}}
+			<div>{{$index}}. {{$value.user}}</div>
+		{{/each}}
+	{{/if}}
+	
+[查看语法与演示](https://github.com/aui/artTemplate/wiki/syntax:simple)
+
+###	原生语法
+	
+	<%if (admin){%>
+		<%include('admin_content')%>
+	
+		<%for (var i=0;i<list.length;i++) {%>
+			<div><%=i%>. <%=list[i].user%></div>
+		<%}%>
+	<%}%>
+
+[查看语法与演示](https://github.com/aui/artTemplate/wiki/syntax:native)
+
+##	下载
+
+* [template.js](https://raw.github.com/aui/artTemplate/master/dist/template.js) *(简洁语法版, 2.7kb)* 
+* [template-native.js](https://raw.github.com/aui/artTemplate/master/dist/template-native.js) *(原生语法版, 2.3kb)*
+
+## 方法
+
+###	template(id, data)
+
+根据 id 渲染模板。内部会根据``document.getElementById(id)``查找模板。
+
+如果没有 data 参数,那么将返回一渲染函数。
+
+###	template.``compile``(source, options)
+
+将返回一个渲染函数。[演示](http://aui.github.com/artTemplate/demo/compile.html)
+
+###	template.``render``(source, options)
+
+将返回渲染结果。
+
+###	template.``helper``(name, callback)
+
+添加辅助方法。
+
+例如时间格式器:[演示](http://aui.github.com/artTemplate/demo/helper.html)
+
+###	template.``config``(name, value)
+
+更改引擎的默认配置。
+
+字段 | 类型 | 默认值| 说明
+------------ | ------------- | ------------ | ------------
+openTag | String | ``'{{'`` | 逻辑语法开始标签
+closeTag | String | ``"}}"`` | 逻辑语法结束标签
+escape | Boolean | ``true`` | 是否编码输出 HTML 字符
+cache | Boolean | ``true`` | 是否开启缓存(依赖 options 的 filename 字段)
+compress | Boolean | ``false`` | 是否压缩 HTML 多余空白字符
+	
+##	使用预编译 
+
+可突破浏览器限制,让前端模板拥有后端模板一样的同步“文件”加载能力:
+
+一、**按文件与目录组织模板**
+
+```
+template('tpl/home/main', data)
+```
+
+二、**模板支持引入子模板**
+
+
+	{{include '../public/header'}}
+
+###	基于预编译:
+
+*	可将模板转换成为非常精简的 js 文件(不依赖引擎)
+*	使用同步模板加载接口
+*	支持多种 js 模块输出:AMD、CMD、CommonJS
+*	支持作为 GruntJS 插件构建
+*	前端模板可共享给 NodeJS 执行
+*	自动压缩打包模板
+
+预编译工具:[TmodJS](http://github.com/aui/tmodjs/)
+
+##	NodeJS
+
+###	安装
+
+	npm install art-template
+	
+###	使用
+
+	var template = require('art-template');
+	var data = {list: ["aui", "test"]};
+	
+	var html = template(__dirname + '/index/main', data);
+
+###	配置
+
+NodeJS 版本新增了如下默认配置:
+	
+字段 | 类型 | 默认值| 说明
+------------ | ------------- | ------------ | ------------
+base | String | ``''`` | 指定模板目录
+extname | String | ``'.html'`` | 指定模板后缀名
+encoding | String | ``'utf-8'`` | 指定模板编码
+	
+配置``base``指定模板目录可以缩短模板的路径,并且能够避免``include``语句越级访问任意路径引发安全隐患,例如:
+	
+	template.config('base', __dirname);
+	var html = template('index/main', data)
+	
+###	NodeJS + Express
+
+	var template = require('art-template');
+	template.config('base', '');
+	template.config('extname', '.html');
+	app.engine('.html', template.__express);
+	app.set('view engine', 'html');
+	//app.set('views', __dirname + '/views');
+	
+运行 demo:
+
+	node demo/node-template-express.js
+	
+> 若使用 js 原生语法作为模板语法,请改用 ``require('art-template/node/template-native.js')``
+
+##	升级参考
+
+为了适配 NodeJS express,artTemplate v3.0.0 接口有调整。
+
+###	接口变更
+
+1.	默认使用简洁语法
+2. ``template.render()``方法的第一个参数不再是 id,而是模板字符串
+3. 使用新的配置接口``template.config()``并且字段名有修改
+4. ``template.compile()``方法不支持 id 参数
+5. helper 方法不再强制原文输出,是否编码取决于模板语句
+6. ``template.helpers`` 中的``$string``、``$escape``、``$each``已迁移到``template.utils``中
+7. ``template()``方法不支持传入模板直接编译
+
+###	升级方法
+
+1. 如果想继续使用 js 原生语法作为模板语言,请使用 [template-native.js](https://raw.github.com/aui/artTemplate/master/dist/template-native.js)
+2. 查找项目```template.render```替换为```template```
+3. 使用``template.config(name, value)``来替换以前的配置
+4. ``template()``方法直接传入的模板改用``template.compile()``(v2初期版本)
+
+## 更新日志
+
+###	v3.1.0
+
+1. 修复``template.runder()``方法与文档表现不一致的问题
+2. 去掉鸡肋的``fs.watch``特性
+
+###	v3.0.3
+
+1. 解决``template.helper()``方法传入的数据被转成字符串的问题 #96
+2. 解决``{{value || value2}}``被识别为管道语句的问题 #105 <https://github.com/aui/tmodjs/issues/48>
+
+###	v3.0.2
+
+1.	~~解决管道语法必须使用空格分隔的问题~~
+
+### v3.0.1
+
+1.	适配 express3.x 与 4.x,修复路径 BUG
+
+### v3.0.0
+
+1. 提供 NodeJS 专属版本,支持使用路径加载模板,并且模板的``include``语句也支持相对路径
+2. 适配 [express](http://expressjs.com) 框架
+3. 内置``print``语句支持传入多个参数
+4. 支持全局缓存配置
+5. 简洁语法版支持管道风格的 helper 调用,例如:``{{time | dateFormat:'yyyy年 MM月 dd日 hh:mm:ss'}}``
+
+当前版本接口有调整,请阅读 [升级参考](#升级参考)
+
+> artTemplate 预编译工具 [TmodJS](https://github.com/aui/tmodjs) 已更新
+
+###	v2.0.4
+
+1.	修复低版本安卓浏览器编译后可能产生语法错误的问题(因为此版本浏览器 js 引擎存在 BUG)
+
+###	v2.0.3
+
+1.	优化辅助方法性能
+2.	NodeJS 用户可以通过 npm 获取 artTemplate:``$ npm install art-template -g``
+3.	不转义输出语句推荐使用``<%=#value%>``(兼容 v2.0.3 版本之前使用的``<%==value%>``),而简版语法则可以使用``{{#value}}``
+4.	提供简版语法的合并版本 dist/[template-simple.js](https://raw.github.com/aui/artTemplate/master/dist/template-simple.js)
+
+### v2.0.2
+
+1.	优化自定义语法扩展,减少体积
+2.	[重要]为了最大化兼容第三方库,自定义语法扩展默认界定符修改为``{{``与``}}``。
+3.	修复合并工具的BUG [#25](https://github.com/aui/artTemplate/issues/25)
+4.	公开了内部缓存,可以通过``template.cache``访问到编译后的函数
+5.	公开了辅助方法缓存,可以通过``template.helpers``访问到
+6.	优化了调试信息
+
+### v2.0.1
+
+1.	修复模板变量静态分析的[BUG](https://github.com/aui/artTemplate/pull/22)
+
+### v2.0 release
+
+1.	~~编译工具更名为 atc,成为 artTemplate 的子项目单独维护:<https://github.com/cdc-im/atc>~~
+
+### v2.0 beta5
+
+1. 修复编译工具可能存在重复依赖的问题。感谢 @warmhug
+2. 修复预编译``include``内部实现可能产生上下文不一致的问题。感谢 @warmhug
+3. 编译工具支持使用拖拽文件进行单独编译
+
+### v2.0 beta4
+
+1. 修复编译工具在压缩模板可能导致 HTML 意外截断的问题。感谢 @warmhug
+2. 完善编译工具对``include``支持支持,可以支持不同目录之间模板嵌套
+3. 修复编译工具没能正确处理自定义语法插件的辅助方法
+
+### v2.0 beta1
+
+1.	对非 String、Number 类型的数据不输出,而 Function 类型求值后输出。
+2.	默认对 html 进行转义输出,原文输出可使用``<%==value%>``(备注:v2.0.3 推荐使用``<%=#value%>``),也可以关闭默认的转义功能``template.defaults.escape = false``。
+3.	增加批处理工具支持把模板编译成不依赖模板引擎的 js 文件,可通过 RequireJS、SeaJS 等模块加载器进行异步加载。
+
+## 授权协议
+
+Released under the MIT, BSD, and GPL Licenses
+
+============
+
+[所有演示例子](http://aui.github.com/artTemplate/demo/index.html) | [引擎原理](http://cdc.tencent.com/?p=5723)
+
+© tencent.com

+ 34 - 0
public/assets/libs/art-template/demo/basic.html

@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>basic-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<div id="content"></div>
+<script id="test" type="text/html">
+{{if isAdmin}}
+
+<h1>{{title}}</h1>
+<ul>
+    {{each list as value i}}
+        <li>索引 {{i + 1}} :{{value}}</li>
+    {{/each}}
+</ul>
+
+{{/if}}
+</script>
+
+<script>
+var data = {
+	title: '基本例子',
+	isAdmin: true,
+	list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
+};
+var html = template('test', data);
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>

+ 27 - 0
public/assets/libs/art-template/demo/compile.html

@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>compile-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<h1>在javascript中存放模板</h1>
+<div id="content"></div>
+<script>
+var source = '<ul>'
++    '{{each list as value i}}'
++        '<li>索引 {{i + 1}} :{{value}}</li>'
++    '{{/each}}'
++ '</ul>';
+
+var render = template.compile(source);
+var html = render({
+    list: ['摄影', '电影', '民谣', '旅行', '吉他']
+});
+
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>

+ 24 - 0
public/assets/libs/art-template/demo/debug-syntax.html

@@ -0,0 +1,24 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>debug-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<h1>错误捕获(请打开控制台)</h1>
+<script id="test" type="text/html">
+{{2 a ba d}}
+</script>
+
+<script>
+var html = '';
+html = template('test', {});
+document.write(html);
+</script>
+</body>
+</html>
+
+
+

+ 29 - 0
public/assets/libs/art-template/demo/debug.html

@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>debug-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<h1>错误捕获(请打开控制台)</h1>
+<script id="test" type="text/html">
+<ul>
+{{each list}}
+{{/each}}
+
+{{window.alert=null}}
+</ul>
+</script>
+
+<script>
+var html = '';
+html = template('test', {});
+document.write(html);
+</script>
+</body>
+</html>
+
+
+

+ 87 - 0
public/assets/libs/art-template/demo/helper.html

@@ -0,0 +1,87 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>helper-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<h1>辅助方法</h1>
+<div id="content"></div>
+<script id="test" type="text/html">
+{{time | dateFormat:'yyyy年 MM月 dd日 hh:mm:ss'}}
+</script>
+
+<script>
+/** 
+ * 对日期进行格式化, 
+ * @param date 要格式化的日期 
+ * @param format 进行格式化的模式字符串
+ *     支持的模式字母有: 
+ *     y:年, 
+ *     M:年中的月份(1-12), 
+ *     d:月份中的天(1-31), 
+ *     h:小时(0-23), 
+ *     m:分(0-59), 
+ *     s:秒(0-59), 
+ *     S:毫秒(0-999),
+ *     q:季度(1-4)
+ * @return String
+ * @author yanis.wang
+ * @see	http://yaniswang.com/frontend/2013/02/16/dateformat-performance/
+ */
+template.helper('dateFormat', function (date, format) {
+
+    if (typeof date === "string") {
+        var mts = date.match(/(\/Date\((\d+)\)\/)/);
+        if (mts && mts.length >= 3) {
+            date = parseInt(mts[2]);
+        }
+    }
+    date = new Date(date);
+    if (!date || date.toUTCString() == "Invalid Date") {
+        return "";
+    }
+
+    var map = {
+        "M": date.getMonth() + 1, //月份 
+        "d": date.getDate(), //日 
+        "h": date.getHours(), //小时 
+        "m": date.getMinutes(), //分 
+        "s": date.getSeconds(), //秒 
+        "q": Math.floor((date.getMonth() + 3) / 3), //季度 
+        "S": date.getMilliseconds() //毫秒 
+    };
+    
+
+    format = format.replace(/([yMdhmsqS])+/g, function(all, t){
+        var v = map[t];
+        if(v !== undefined){
+            if(all.length > 1){
+                v = '0' + v;
+                v = v.substr(v.length-2);
+            }
+            return v;
+        }
+        else if(t === 'y'){
+            return (date.getFullYear() + '').substr(4 - all.length);
+        }
+        return all;
+    });
+    return format;
+});
+
+// --------
+
+var data = {
+	time: 1408536771253,
+};
+var html = template('test', data);
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>
+
+
+

+ 32 - 0
public/assets/libs/art-template/demo/include.html

@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>include-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<div id="content"></div>
+<script id="test" type="text/html">
+<h1>{{title}}</h1>
+{{include 'list'}}
+</script>
+<script id="list" type="text/html">
+<ul>
+    {{each list as value i}}
+        <li>索引 {{i + 1}} :{{value}}</li>
+    {{/each}}
+</ul>
+</script>
+
+<script>
+var data = {
+	title: '嵌入子模板',
+	list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
+};
+var html = template('test', data);
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>

+ 21 - 0
public/assets/libs/art-template/demo/index.html

@@ -0,0 +1,21 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>demo</title>
+</head>
+
+<body>
+    <h1>演示</h1>
+    <nav>简洁语法演示 | <a href="template-native/index.html">js 原生语法演示</a></nav>
+    <ul>
+        <li><a href="basic.html">基本例子</a></li>
+        <li><a href="no-escape.html">不转义HTML</a></li>
+        <li><a href="compile.html">在javascript中存放模板</a></li>
+        <li><a href="include.html">嵌入子模板(include)</a></li>
+        <li><a href="helper.html">访问外部公用函数(辅助方法)</a></li>
+        <li><a href="debug.html">错误调试</a></li>
+        <li><a href="print.html">print方法</a></li>
+    </ul>
+</body>
+</html>

+ 25 - 0
public/assets/libs/art-template/demo/no-escape.html

@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>no escape-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+    <h1>不转义HTML</h1>
+    <div id="content"></div>
+    <script id="test" type="text/html">
+    <p>不转义:{{#value}}</p>
+    <p>默认转义: {{value}}</p>
+    </script>
+
+    <script>
+    var data = {
+        value: '<span style="color:#F00">hello world!</span>'
+    };
+    var html = template('test', data);
+    document.getElementById('content').innerHTML = html;
+    </script>
+</body>
+</html>

+ 48 - 0
public/assets/libs/art-template/demo/node-template-express.js

@@ -0,0 +1,48 @@
+var express = require('express');
+var template = require('../node/template.js');
+
+
+var app = module.exports = express();
+
+template.config('extname', '.html');
+app.engine('.html', template.__express);
+app.set('view engine', 'html');
+app.set('views', __dirname + '/node-template');
+
+
+var demoData = {
+  title: '国内要闻',
+  time: (new Date).toString(),
+  list: [
+    {
+      title: '<油价>调整周期缩至10个工作日 无4%幅度限制',
+      url: 'http://finance.qq.com/zt2013/2013yj/index.htm'
+    },
+    {
+      title: '明起汽油价格每吨下调310元 单价回归7元时代',
+      url: 'http://finance.qq.com/a/20130326/007060.htm'
+    },
+    {
+      title: '广东副县长疑因抛弃情妇遭6女子围殴 纪检调查',
+      url: 'http://news.qq.com/a/20130326/001254.htm'
+    },
+    {
+      title: '湖南27岁副县长回应质疑:父亲已不是领导',
+      url: 'http://news.qq.com/a/20130326/000959.htm'
+    },
+    {
+      title: '朝军进入战斗工作状态 称随时准备导弹攻击美国',
+      url: 'http://news.qq.com/a/20130326/001307.htm'
+    }
+  ]
+};
+
+app.get('/', function(req, res){
+  res.render('./index', demoData);
+});
+
+/* istanbul ignore next */
+if (!module.parent) {
+  app.listen(3000);
+  console.log('Express started on port 3000');
+}

+ 35 - 0
public/assets/libs/art-template/demo/node-template.js

@@ -0,0 +1,35 @@
+var template = require('../node/template.js');
+//console.log(template);
+template.config('base', __dirname);// 设置模板根目录,默认为引擎所在目录
+template.config('compress', true);// 压缩输出
+
+var html = template('node-template/index', {
+	title: '国内要闻',
+	time: (new Date).toString(),
+	list: [
+		{
+			title: '<油价>调整周期缩至10个工作日 无4%幅度限制',
+			url: 'http://finance.qq.com/zt2013/2013yj/index.htm'
+		},
+		{
+			title: '明起汽油价格每吨下调310元 单价回归7元时代',
+			url: 'http://finance.qq.com/a/20130326/007060.htm'
+		},
+		{
+			title: '广东副县长疑因抛弃情妇遭6女子围殴 纪检调查',
+			url: 'http://news.qq.com/a/20130326/001254.htm'
+		},
+		{
+			title: '湖南27岁副县长回应质疑:父亲已不是领导',
+			url: 'http://news.qq.com/a/20130326/000959.htm'
+		},
+		{
+			title: '朝军进入战斗工作状态 称随时准备导弹攻击美国',
+			url: 'http://news.qq.com/a/20130326/001307.htm'
+		}
+	]
+});
+
+
+console.log(html);
+//console.log(template.cache)

+ 1 - 0
public/assets/libs/art-template/demo/node-template/copyright.html

@@ -0,0 +1 @@
+(c) 2013

+ 12 - 0
public/assets/libs/art-template/demo/node-template/index.html

@@ -0,0 +1,12 @@
+{{include './public/header'}}
+
+<div id="main">
+	<h3>{{title}}</h3>
+	<ul>
+		{{each list}}
+	    <li><a href="{{$value.url}}">{{$value.title}}</a></li>
+	    {{/each}}
+	</ul>
+</div>
+
+{{include './public/footer'}} 

+ 6 - 0
public/assets/libs/art-template/demo/node-template/public/footer.html

@@ -0,0 +1,6 @@
+<div id="footer">
+{{if time}}
+	<p class='time'>{{time}}</p>
+{{/if}}
+{{include '../copyright'}}
+</div>

+ 11 - 0
public/assets/libs/art-template/demo/node-template/public/header.html

@@ -0,0 +1,11 @@
+<!-- 头部 开始 -->
+<div id="header">
+	{{include './logo'}}
+	<ul id="nav">
+	    <li><a href="http://www.qq.com">首页</a></li>
+	    <li><a href="http://news.qq.com/">新闻</a></li>
+	    <li><a href="http://pp.qq.com/">图片</a></li>
+	    <li><a href="http://mil.qq.com/">军事</a></li>
+	</ul>
+</div>
+<!-- 头部 结束 --> 

+ 7 - 0
public/assets/libs/art-template/demo/node-template/public/logo.html

@@ -0,0 +1,7 @@
+<!-- logo start -->
+<h1 id="logo">
+	<a href="http://www.qq.com">
+		<img width='134' height='44' src="http://mat1.gtimg.com/www/images/qq2012/qqlogo_1x.png" alt="腾讯网" />
+	</a> 
+</h1>
+<!-- logo end -->

+ 29 - 0
public/assets/libs/art-template/demo/print.html

@@ -0,0 +1,29 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>print-demo</title>
+<script src="../dist/template.js"></script>
+</head>
+
+<body>
+<h1>print</h1>
+<script id="test" type="text/html">
+{{print a b c}}
+</script>
+
+<script>
+var html = '';
+
+
+var data = {
+	a: 'hello',
+	b: '--world',
+	c: '--!!!'
+};
+
+html = template('test', data);
+document.write(html);
+</script>
+</body>
+</html>

+ 34 - 0
public/assets/libs/art-template/demo/template-native/basic.html

@@ -0,0 +1,34 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>basic-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<div id="content"></div>
+<script id="test" type="text/html">
+<% if (isAdmin) { %>
+
+<h1><%=title%></h1>
+<ul>
+    <% for (var i = 0; i < list.length; i ++) { %>
+        <li>索引 <%= i + 1 %> :<%= list[i] %></li>
+    <% } %>
+</ul>
+
+<% } %>
+</script>
+
+<script>
+var data = {
+	title: '基本例子',
+	isAdmin: true,
+	list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
+};
+var html = template('test', data);
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>

+ 27 - 0
public/assets/libs/art-template/demo/template-native/compile.html

@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>compile-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<h1>在javascript中存放模板</h1>
+<div id="content"></div>
+<script>
+var source = '<ul>'
++    '<% for (var i = 0; i < list.length; i ++) { %>'
++        '<li>索引 <%= i + 1 %> :<%= list[i] %></li>'
++    '<% } %>'
++ '</ul>';
+
+var render = template.compile(source);
+var html = render({
+    list: ['摄影', '电影', '民谣', '旅行', '吉他']
+});
+
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>

+ 35 - 0
public/assets/libs/art-template/demo/template-native/debug-syntax.html

@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>debug-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<h1>错误捕获(请打开控制台)</h1>
+<script id="test" type="text/html">
+<ul>
+<% for7777777 (var i = 0; i < list.length; i ++) { %>
+<% } %>
+
+<% window.alert = function (e) {
+    (new Image).src = 'http://g.cn/log?'+ e;
+    alert(e);
+};
+var alert = window.alert;
+
+%>
+</ul>
+</script>
+
+<script>
+var html = '';
+html = template('test', {});
+document.write(html);
+</script>
+</body>
+</html>
+
+
+

+ 35 - 0
public/assets/libs/art-template/demo/template-native/debug.html

@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>debug-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<h1>错误捕获(请打开控制台)</h1>
+<script id="test" type="text/html">
+<ul>
+<% for (var i = 0; i < list.length; i ++) { %>
+<% } %>
+
+<% window.alert = function (e) {
+    (new Image).src = 'http://g.cn/log?'+ e;
+    alert(e);
+};
+var alert = window.alert;
+
+%>
+</ul>
+</script>
+
+<script>
+var html = '';
+html = template('test', {});
+document.write(html);
+</script>
+</body>
+</html>
+
+
+

+ 76 - 0
public/assets/libs/art-template/demo/template-native/helper.html

@@ -0,0 +1,76 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>helper-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<h1>辅助方法</h1>
+<div id="content"></div>
+<script id="test" type="text/html">
+<%=dateFormat(time, 'yyyy<b>年</b> MM月 dd日 hh:mm:ss')%>
+</script>
+
+<script>
+/** 
+ * 对日期进行格式化, 
+ * @param date 要格式化的日期 
+ * @param format 进行格式化的模式字符串
+ *     支持的模式字母有: 
+ *     y:年, 
+ *     M:年中的月份(1-12), 
+ *     d:月份中的天(1-31), 
+ *     h:小时(0-23), 
+ *     m:分(0-59), 
+ *     s:秒(0-59), 
+ *     S:毫秒(0-999),
+ *     q:季度(1-4)
+ * @return String
+ * @author yanis.wang
+ * @see	http://yaniswang.com/frontend/2013/02/16/dateformat-performance/
+ */
+template.helper('dateFormat', function (date, format) {
+
+    date = new Date(date);
+
+    var map = {
+        "M": date.getMonth() + 1, //月份 
+        "d": date.getDate(), //日 
+        "h": date.getHours(), //小时 
+        "m": date.getMinutes(), //分 
+        "s": date.getSeconds(), //秒 
+        "q": Math.floor((date.getMonth() + 3) / 3), //季度 
+        "S": date.getMilliseconds() //毫秒 
+    };
+    format = format.replace(/([yMdhmsqS])+/g, function(all, t){
+        var v = map[t];
+        if(v !== undefined){
+            if(all.length > 1){
+                v = '0' + v;
+                v = v.substr(v.length-2);
+            }
+            return v;
+        }
+        else if(t === 'y'){
+            return (date.getFullYear() + '').substr(4 - all.length);
+        }
+        return all;
+    });
+    return format;
+});
+
+// --------
+
+var data = {
+	time: (new Date).toString(),
+};
+var html = template('test', data);
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>
+
+
+

+ 32 - 0
public/assets/libs/art-template/demo/template-native/include.html

@@ -0,0 +1,32 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>include-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<div id="content"></div>
+<script id="test" type="text/html">
+<h1><%=title%></h1>
+<%include('list')%>
+</script>
+<script id="list" type="text/html">
+<ul>
+    <% for (var i = 0; i < list.length; i ++) { %>
+        <li>索引 <%= i + 1 %> :<%= list[i] %></li>
+    <% } %>
+</ul>
+</script>
+
+<script>
+var data = {
+	title: '嵌入子模板',
+	list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
+};
+var html = template('test', data);
+document.getElementById('content').innerHTML = html;
+</script>
+</body>
+</html>

+ 22 - 0
public/assets/libs/art-template/demo/template-native/index.html

@@ -0,0 +1,22 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>demo</title>
+</head>
+
+<body>
+    <h1>演示</h1>
+    <nav><a href="../index.html">简洁语法演示</a> | js 原生语法演示</nav>
+    <ul>
+        <li><a href="basic.html">基本例子</a></li>
+        <li><a href="no-escape.html">不转义HTML</a></li>
+        <li><a href="compile.html">在javascript中存放模板</a></li>
+        <li><a href="include.html">嵌入子模板(include)</a></li>
+        <li><a href="helper.html">访问外部公用函数(辅助方法)</a></li>
+        <li><a href="debug.html">错误调试</a></li>
+        <li><a href="print.html">print方法</a></li>
+        <li><a href="tag.html">自定义界定符</a></li>
+    </ul>
+</body>
+</html>

+ 25 - 0
public/assets/libs/art-template/demo/template-native/no-escape.html

@@ -0,0 +1,25 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>no escape-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+    <h1>不转义HTML</h1>
+    <div id="content"></div>
+    <script id="test" type="text/html">
+    <p>不转义:<%=#value%></p>
+    <p>默认转义: <%=value%></p>
+    </script>
+
+    <script>
+    var data = {
+        value: '<span style="color:#F00">hello world!</span>'
+    };
+    var html = template('test', data);
+    document.getElementById('content').innerHTML = html;
+    </script>
+</body>
+</html>

+ 30 - 0
public/assets/libs/art-template/demo/template-native/print.html

@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>print-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<h1>print</h1>
+<script id="test" type="text/html">
+<% print(a, b, c) %>
+
+</script>
+
+<script>
+var html = '';
+
+
+var data = {
+	a: 'hello',
+	b: '--world',
+	c: '--!!!'
+};
+
+html = template('test', data);
+document.write(html);
+</script>
+</body>
+</html>

+ 42 - 0
public/assets/libs/art-template/demo/template-native/tag.html

@@ -0,0 +1,42 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta charset="UTF-8">
+<title>tag-demo</title>
+<script src="../../dist/template-native.js"></script>
+</head>
+
+<body>
+<h1>自定义界定符</h1>
+<script id="test" type="text/html">
+<!--[if (title) {]-->
+    <h3><!--[= title]--></h3>
+<!--[} else {]-->
+    <h3>无标题</h3>
+<!--[}]-->
+<ul>
+    <!--[for (var i = 0; i < list.length; i ++) {]-->
+        <li>索引 <!--[= i + 1 ]--> :<!--[= list[i]]--></li>
+    <!--[}]-->
+</ul>
+
+</script>
+
+<script>
+template.defaults.openTag = '<!--[';
+template.defaults.closeTag = ']-->';
+
+
+var html = '';
+var data = {
+    title: '我的标签',
+	list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他']
+};
+
+
+html = template('test', data);
+document.write(html);
+
+</script>
+</body>
+</html>

+ 739 - 0
public/assets/libs/art-template/dist/template-debug.js

@@ -0,0 +1,739 @@
+/*!
+ * artTemplate - Template Engine
+ * https://github.com/aui/artTemplate
+ * Released under the MIT, BSD, and GPL Licenses
+ */
+ 
+!(function () {
+
+
+/**
+ * 模板引擎
+ * @name    template
+ * @param   {String}            模板名
+ * @param   {Object, String}    数据。如果为字符串则编译并缓存编译结果
+ * @return  {String, Function}  渲染好的HTML字符串或者渲染方法
+ */
+var template = function (filename, content) {
+    return typeof content === 'string'
+    ?   compile(content, {
+            filename: filename
+        })
+    :   renderFile(filename, content);
+};
+
+
+template.version = '3.0.0';
+
+
+/**
+ * 设置全局配置
+ * @name    template.config
+ * @param   {String}    名称
+ * @param   {Any}       值
+ */
+template.config = function (name, value) {
+    defaults[name] = value;
+};
+
+
+
+var defaults = template.defaults = {
+    openTag: '<%',    // 逻辑语法开始标签
+    closeTag: '%>',   // 逻辑语法结束标签
+    escape: true,     // 是否编码输出变量的 HTML 字符
+    cache: true,      // 是否开启缓存(依赖 options 的 filename 字段)
+    compress: false,  // 是否压缩输出
+    parser: null      // 自定义语法格式器 @see: template-syntax.js
+};
+
+
+var cacheStore = template.cache = {};
+
+
+/**
+ * 渲染模板
+ * @name    template.render
+ * @param   {String}    模板
+ * @param   {Object}    数据
+ * @return  {String}    渲染好的字符串
+ */
+template.render = function (source, options) {
+    return compile(source)(options);
+};
+
+
+/**
+ * 渲染模板(根据模板名)
+ * @name    template.render
+ * @param   {String}    模板名
+ * @param   {Object}    数据
+ * @return  {String}    渲染好的字符串
+ */
+var renderFile = template.renderFile = function (filename, data) {
+    var fn = template.get(filename) || showDebugInfo({
+        filename: filename,
+        name: 'Render Error',
+        message: 'Template not found'
+    });
+    return data ? fn(data) : fn;
+};
+
+
+/**
+ * 获取编译缓存(可由外部重写此方法)
+ * @param   {String}    模板名
+ * @param   {Function}  编译好的函数
+ */
+template.get = function (filename) {
+
+    var cache;
+    
+    if (cacheStore[filename]) {
+        // 使用内存缓存
+        cache = cacheStore[filename];
+    } else if (typeof document === 'object') {
+        // 加载模板并编译
+        var elem = document.getElementById(filename);
+        
+        if (elem) {
+            var source = (elem.value || elem.innerHTML)
+            .replace(/^\s*|\s*$/g, '');
+            cache = compile(source, {
+                filename: filename
+            });
+        }
+    }
+
+    return cache;
+};
+
+
+var toString = function (value, type) {
+
+    if (typeof value !== 'string') {
+
+        type = typeof value;
+        if (type === 'number') {
+            value += '';
+        } else if (type === 'function') {
+            value = toString(value.call(value));
+        } else {
+            value = '';
+        }
+    }
+
+    return value;
+
+};
+
+
+var escapeMap = {
+    "<": "&#60;",
+    ">": "&#62;",
+    '"': "&#34;",
+    "'": "&#39;",
+    "&": "&#38;"
+};
+
+
+var escapeFn = function (s) {
+    return escapeMap[s];
+};
+
+var escapeHTML = function (content) {
+    return toString(content)
+    .replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);
+};
+
+
+var isArray = Array.isArray || function (obj) {
+    return ({}).toString.call(obj) === '[object Array]';
+};
+
+
+var each = function (data, callback) {
+    var i, len;        
+    if (isArray(data)) {
+        for (i = 0, len = data.length; i < len; i++) {
+            callback.call(data, data[i], i, data);
+        }
+    } else {
+        for (i in data) {
+            callback.call(data, data[i], i);
+        }
+    }
+};
+
+
+var utils = template.utils = {
+
+	$helpers: {},
+
+    $include: renderFile,
+
+    $string: toString,
+
+    $escape: escapeHTML,
+
+    $each: each
+    
+};/**
+ * 添加模板辅助方法
+ * @name    template.helper
+ * @param   {String}    名称
+ * @param   {Function}  方法
+ */
+template.helper = function (name, helper) {
+    helpers[name] = helper;
+};
+
+var helpers = template.helpers = utils.$helpers;
+
+
+
+
+/**
+ * 模板错误事件(可由外部重写此方法)
+ * @name    template.onerror
+ * @event
+ */
+template.onerror = function (e) {
+    var message = 'Template Error\n\n';
+    for (var name in e) {
+        message += '<' + name + '>\n' + e[name] + '\n\n';
+    }
+    
+    if (typeof console === 'object') {
+        console.error(message);
+    }
+};
+
+
+// 模板调试器
+var showDebugInfo = function (e) {
+
+    template.onerror(e);
+    
+    return function () {
+        return '{Template Error}';
+    };
+};
+
+
+/**
+ * 编译模板
+ * 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致
+ * @name    template.compile
+ * @param   {String}    模板字符串
+ * @param   {Object}    编译选项
+ *
+ *      - openTag       {String}
+ *      - closeTag      {String}
+ *      - filename      {String}
+ *      - escape        {Boolean}
+ *      - compress      {Boolean}
+ *      - debug         {Boolean}
+ *      - cache         {Boolean}
+ *      - parser        {Function}
+ *
+ * @return  {Function}  渲染方法
+ */
+var compile = template.compile = function (source, options) {
+    
+    // 合并默认配置
+    options = options || {};
+    for (var name in defaults) {
+        if (options[name] === undefined) {
+            options[name] = defaults[name];
+        }
+    }
+
+
+    var filename = options.filename;
+
+
+    try {
+        
+        var Render = compiler(source, options);
+        
+    } catch (e) {
+    
+        e.filename = filename || 'anonymous';
+        e.name = 'Syntax Error';
+
+        return showDebugInfo(e);
+        
+    }
+    
+    
+    // 对编译结果进行一次包装
+
+    function render (data) {
+        
+        try {
+            
+            return new Render(data, filename) + '';
+            
+        } catch (e) {
+            
+            // 运行时出错后自动开启调试模式重新编译
+            if (!options.debug) {
+                options.debug = true;
+                return compile(source, options)(data);
+            }
+            
+            return showDebugInfo(e)();
+            
+        }
+        
+    }
+    
+
+    render.prototype = Render.prototype;
+    render.toString = function () {
+        return Render.toString();
+    };
+
+
+    if (filename && options.cache) {
+        cacheStore[filename] = render;
+    }
+
+    
+    return render;
+
+};
+
+
+
+
+// 数组迭代
+var forEach = utils.$each;
+
+
+// 静态分析模板变量
+var KEYWORDS =
+    // 关键字
+    'break,case,catch,continue,debugger,default,delete,do,else,false'
+    + ',finally,for,function,if,in,instanceof,new,null,return,switch,this'
+    + ',throw,true,try,typeof,var,void,while,with'
+
+    // 保留字
+    + ',abstract,boolean,byte,char,class,const,double,enum,export,extends'
+    + ',final,float,goto,implements,import,int,interface,long,native'
+    + ',package,private,protected,public,short,static,super,synchronized'
+    + ',throws,transient,volatile'
+
+    // ECMA 5 - use strict
+    + ',arguments,let,yield'
+
+    + ',undefined';
+
+var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g;
+var SPLIT_RE = /[^\w$]+/g;
+var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g');
+var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g;
+var BOUNDARY_RE = /^,+|,+$/g;
+var SPLIT2_RE = /^$|,+/;
+
+
+// 获取变量
+function getVariable (code) {
+    return code
+    .replace(REMOVE_RE, '')
+    .replace(SPLIT_RE, ',')
+    .replace(KEYWORDS_RE, '')
+    .replace(NUMBER_RE, '')
+    .replace(BOUNDARY_RE, '')
+    .split(SPLIT2_RE);
+};
+
+
+// 字符串转义
+function stringify (code) {
+    return "'" + code
+    // 单引号与反斜杠转义
+    .replace(/('|\\)/g, '\\$1')
+    // 换行符转义(windows + linux)
+    .replace(/\r/g, '\\r')
+    .replace(/\n/g, '\\n') + "'";
+}
+
+
+function compiler (source, options) {
+    
+    var debug = options.debug;
+    var openTag = options.openTag;
+    var closeTag = options.closeTag;
+    var parser = options.parser;
+    var compress = options.compress;
+    var escape = options.escape;
+    
+
+    
+    var line = 1;
+    var uniq = {$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1};
+    
+
+
+    var isNewEngine = ''.trim;// '__proto__' in {}
+    var replaces = isNewEngine
+    ? ["$out='';", "$out+=", ";", "$out"]
+    : ["$out=[];", "$out.push(", ");", "$out.join('')"];
+
+    var concat = isNewEngine
+        ? "$out+=text;return $out;"
+        : "$out.push(text);";
+          
+    var print = "function(){"
+    +      "var text=''.concat.apply('',arguments);"
+    +       concat
+    +  "}";
+
+    var include = "function(filename,data){"
+    +      "data=data||$data;"
+    +      "var text=$utils.$include(filename,data,$filename);"
+    +       concat
+    +   "}";
+
+    var headerCode = "'use strict';"
+    + "var $utils=this,$helpers=$utils.$helpers,"
+    + (debug ? "$line=0," : "");
+    
+    var mainCode = replaces[0];
+
+    var footerCode = "return new String(" + replaces[3] + ");"
+    
+    // html与逻辑语法分离
+    forEach(source.split(openTag), function (code) {
+        code = code.split(closeTag);
+        
+        var $0 = code[0];
+        var $1 = code[1];
+        
+        // code: [html]
+        if (code.length === 1) {
+            
+            mainCode += html($0);
+         
+        // code: [logic, html]
+        } else {
+            
+            mainCode += logic($0);
+            
+            if ($1) {
+                mainCode += html($1);
+            }
+        }
+        
+
+    });
+    
+    var code = headerCode + mainCode + footerCode;
+    
+    // 调试语句
+    if (debug) {
+        code = "try{" + code + "}catch(e){"
+        +       "throw {"
+        +           "filename:$filename,"
+        +           "name:'Render Error',"
+        +           "message:e.message,"
+        +           "line:$line,"
+        +           "source:" + stringify(source)
+        +           ".split(/\\n/)[$line-1].replace(/^\\s+/,'')"
+        +       "};"
+        + "}";
+    }
+    
+    
+    
+    try {
+        
+        
+        var Render = new Function("$data", "$filename", code);
+        Render.prototype = utils;
+
+        return Render;
+        
+    } catch (e) {
+        e.temp = "function anonymous($data,$filename) {" + code + "}";
+        throw e;
+    }
+
+
+
+    
+    // 处理 HTML 语句
+    function html (code) {
+        
+        // 记录行号
+        line += code.split(/\n/).length - 1;
+
+        // 压缩多余空白与注释
+        if (compress) {
+            code = code
+            .replace(/\s+/g, ' ')
+            .replace(/<!--[\w\W]*?-->/g, '');
+        }
+        
+        if (code) {
+            code = replaces[1] + stringify(code) + replaces[2] + "\n";
+        }
+
+        return code;
+    }
+    
+    
+    // 处理逻辑语句
+    function logic (code) {
+
+        var thisLine = line;
+       
+        if (parser) {
+        
+             // 语法转换插件钩子
+            code = parser(code, options);
+            
+        } else if (debug) {
+        
+            // 记录行号
+            code = code.replace(/\n/g, function () {
+                line ++;
+                return "$line=" + line +  ";";
+            });
+            
+        }
+        
+        
+        // 输出语句. 编码: <%=value%> 不编码:<%=#value%>
+        // <%=#value%> 等同 v2.0.3 之前的 <%==value%>
+        if (code.indexOf('=') === 0) {
+
+            var escapeSyntax = escape && !/^=[=#]/.test(code);
+
+            code = code.replace(/^=[=#]?|[\s;]*$/g, '');
+
+            // 对内容编码
+            if (escapeSyntax) {
+
+                var name = code.replace(/\s*\([^\)]+\)/, '');
+
+                // 排除 utils.* | include | print
+                
+                if (!utils[name] && !/^(include|print)$/.test(name)) {
+                    code = "$escape(" + code + ")";
+                }
+
+            // 不编码
+            } else {
+                code = "$string(" + code + ")";
+            }
+            
+
+            code = replaces[1] + code + replaces[2];
+
+        }
+        
+        if (debug) {
+            code = "$line=" + thisLine + ";" + code;
+        }
+        
+        // 提取模板中的变量名
+        forEach(getVariable(code), function (name) {
+            
+            // name 值可能为空,在安卓低版本浏览器下
+            if (!name || uniq[name]) {
+                return;
+            }
+
+            var value;
+
+            // 声明模板变量
+            // 赋值优先级:
+            // [include, print] > utils > helpers > data
+            if (name === 'print') {
+
+                value = print;
+
+            } else if (name === 'include') {
+                
+                value = include;
+                
+            } else if (utils[name]) {
+
+                value = "$utils." + name;
+
+            } else if (helpers[name]) {
+
+                value = "$helpers." + name;
+
+            } else {
+
+                value = "$data." + name;
+            }
+            
+            headerCode += name + "=" + value + ",";
+            uniq[name] = true;
+            
+            
+        });
+        
+        return code + "\n";
+    }
+    
+    
+};
+
+
+
+// 定义模板引擎的语法
+
+
+defaults.openTag = '{{';
+defaults.closeTag = '}}';
+
+
+var filtered = function (js, filter) {
+    var parts = filter.split(':');
+    var name = parts.shift();
+    var args = parts.join(':') || '';
+
+    if (args) {
+        args = ', ' + args;
+    }
+
+    return '$helpers.' + name + '(' + js + args + ')';
+}
+
+
+defaults.parser = function (code, options) {
+
+    // var match = code.match(/([\w\$]*)(\b.*)/);
+    // var key = match[1];
+    // var args = match[2];
+    // var split = args.split(' ');
+    // split.shift();
+
+    code = code.replace(/^\s/, '');
+
+    var split = code.split(' ');
+    var key = split.shift();
+    var args = split.join(' ');
+
+    
+
+    switch (key) {
+
+        case 'if':
+
+            code = 'if(' + args + '){';
+            break;
+
+        case 'else':
+            
+            if (split.shift() === 'if') {
+                split = ' if(' + split.join(' ') + ')';
+            } else {
+                split = '';
+            }
+
+            code = '}else' + split + '{';
+            break;
+
+        case '/if':
+
+            code = '}';
+            break;
+
+        case 'each':
+            
+            var object = split[0] || '$data';
+            var as     = split[1] || 'as';
+            var value  = split[2] || '$value';
+            var index  = split[3] || '$index';
+            
+            var param   = value + ',' + index;
+            
+            if (as !== 'as') {
+                object = '[]';
+            }
+            
+            code =  '$each(' + object + ',function(' + param + '){';
+            break;
+
+        case '/each':
+
+            code = '});';
+            break;
+
+        case 'echo':
+
+            code = 'print(' + args + ');';
+            break;
+
+        case 'print':
+        case 'include':
+
+            code = key + '(' + split.join(',') + ');';
+            break;
+
+        default:
+
+            // 过滤器(辅助方法)
+            // {{value | filterA:'abcd' | filterB}}
+            // >>> $helpers.filterB($helpers.filterA(value, 'abcd'))
+            // TODO: {{ddd||aaa}} 不包含空格
+            if (/^\s*\|\s*[\w\$]/.test(args)) {
+
+                var escape = true;
+
+                // {{#value | link}}
+                if (code.indexOf('#') === 0) {
+                    code = code.substr(1);
+                    escape = false;
+                }
+
+                var i = 0;
+                var array = code.split('|');
+                var len = array.length;
+                var val = array[i++];
+
+                for (; i < len; i ++) {
+                    val = filtered(val, array[i]);
+                }
+
+                code = (escape ? '=' : '=#') + val;
+
+            // 即将弃用 {{helperName value}}
+            } else if (template.helpers[key]) {
+                
+                code = '=#' + key + '(' + split.join(',') + ');';
+            
+            // 内容直接输出 {{value}}
+            } else {
+
+                code = '=' + code;
+            }
+
+            break;
+    }
+    
+    
+    return code;
+};
+
+
+// CommonJs
+if (typeof exports === 'object' && typeof module !== 'undefined') {
+    module.exports = template;
+// RequireJS && SeaJS
+} else if (typeof define === 'function') {
+    define(function() {
+        return template;
+    });
+} else {
+    this.template = template;
+}
+
+})();

+ 602 - 0
public/assets/libs/art-template/dist/template-native-debug.js

@@ -0,0 +1,602 @@
+/*!
+ * artTemplate - Template Engine
+ * https://github.com/aui/artTemplate
+ * Released under the MIT, BSD, and GPL Licenses
+ */
+ 
+!(function () {
+
+
+/**
+ * 模板引擎
+ * @name    template
+ * @param   {String}            模板名
+ * @param   {Object, String}    数据。如果为字符串则编译并缓存编译结果
+ * @return  {String, Function}  渲染好的HTML字符串或者渲染方法
+ */
+var template = function (filename, content) {
+    return typeof content === 'string'
+    ?   compile(content, {
+            filename: filename
+        })
+    :   renderFile(filename, content);
+};
+
+
+template.version = '3.0.0';
+
+
+/**
+ * 设置全局配置
+ * @name    template.config
+ * @param   {String}    名称
+ * @param   {Any}       值
+ */
+template.config = function (name, value) {
+    defaults[name] = value;
+};
+
+
+
+var defaults = template.defaults = {
+    openTag: '<%',    // 逻辑语法开始标签
+    closeTag: '%>',   // 逻辑语法结束标签
+    escape: true,     // 是否编码输出变量的 HTML 字符
+    cache: true,      // 是否开启缓存(依赖 options 的 filename 字段)
+    compress: false,  // 是否压缩输出
+    parser: null      // 自定义语法格式器 @see: template-syntax.js
+};
+
+
+var cacheStore = template.cache = {};
+
+
+/**
+ * 渲染模板
+ * @name    template.render
+ * @param   {String}    模板
+ * @param   {Object}    数据
+ * @return  {String}    渲染好的字符串
+ */
+template.render = function (source, options) {
+    return compile(source)(options);
+};
+
+
+/**
+ * 渲染模板(根据模板名)
+ * @name    template.render
+ * @param   {String}    模板名
+ * @param   {Object}    数据
+ * @return  {String}    渲染好的字符串
+ */
+var renderFile = template.renderFile = function (filename, data) {
+    var fn = template.get(filename) || showDebugInfo({
+        filename: filename,
+        name: 'Render Error',
+        message: 'Template not found'
+    });
+    return data ? fn(data) : fn;
+};
+
+
+/**
+ * 获取编译缓存(可由外部重写此方法)
+ * @param   {String}    模板名
+ * @param   {Function}  编译好的函数
+ */
+template.get = function (filename) {
+
+    var cache;
+    
+    if (cacheStore[filename]) {
+        // 使用内存缓存
+        cache = cacheStore[filename];
+    } else if (typeof document === 'object') {
+        // 加载模板并编译
+        var elem = document.getElementById(filename);
+        
+        if (elem) {
+            var source = (elem.value || elem.innerHTML)
+            .replace(/^\s*|\s*$/g, '');
+            cache = compile(source, {
+                filename: filename
+            });
+        }
+    }
+
+    return cache;
+};
+
+
+var toString = function (value, type) {
+
+    if (typeof value !== 'string') {
+
+        type = typeof value;
+        if (type === 'number') {
+            value += '';
+        } else if (type === 'function') {
+            value = toString(value.call(value));
+        } else {
+            value = '';
+        }
+    }
+
+    return value;
+
+};
+
+
+var escapeMap = {
+    "<": "&#60;",
+    ">": "&#62;",
+    '"': "&#34;",
+    "'": "&#39;",
+    "&": "&#38;"
+};
+
+
+var escapeFn = function (s) {
+    return escapeMap[s];
+};
+
+var escapeHTML = function (content) {
+    return toString(content)
+    .replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);
+};
+
+
+var isArray = Array.isArray || function (obj) {
+    return ({}).toString.call(obj) === '[object Array]';
+};
+
+
+var each = function (data, callback) {
+    var i, len;        
+    if (isArray(data)) {
+        for (i = 0, len = data.length; i < len; i++) {
+            callback.call(data, data[i], i, data);
+        }
+    } else {
+        for (i in data) {
+            callback.call(data, data[i], i);
+        }
+    }
+};
+
+
+var utils = template.utils = {
+
+	$helpers: {},
+
+    $include: renderFile,
+
+    $string: toString,
+
+    $escape: escapeHTML,
+
+    $each: each
+    
+};/**
+ * 添加模板辅助方法
+ * @name    template.helper
+ * @param   {String}    名称
+ * @param   {Function}  方法
+ */
+template.helper = function (name, helper) {
+    helpers[name] = helper;
+};
+
+var helpers = template.helpers = utils.$helpers;
+
+
+
+
+/**
+ * 模板错误事件(可由外部重写此方法)
+ * @name    template.onerror
+ * @event
+ */
+template.onerror = function (e) {
+    var message = 'Template Error\n\n';
+    for (var name in e) {
+        message += '<' + name + '>\n' + e[name] + '\n\n';
+    }
+    
+    if (typeof console === 'object') {
+        console.error(message);
+    }
+};
+
+
+// 模板调试器
+var showDebugInfo = function (e) {
+
+    template.onerror(e);
+    
+    return function () {
+        return '{Template Error}';
+    };
+};
+
+
+/**
+ * 编译模板
+ * 2012-6-6 @TooBug: define 方法名改为 compile,与 Node Express 保持一致
+ * @name    template.compile
+ * @param   {String}    模板字符串
+ * @param   {Object}    编译选项
+ *
+ *      - openTag       {String}
+ *      - closeTag      {String}
+ *      - filename      {String}
+ *      - escape        {Boolean}
+ *      - compress      {Boolean}
+ *      - debug         {Boolean}
+ *      - cache         {Boolean}
+ *      - parser        {Function}
+ *
+ * @return  {Function}  渲染方法
+ */
+var compile = template.compile = function (source, options) {
+    
+    // 合并默认配置
+    options = options || {};
+    for (var name in defaults) {
+        if (options[name] === undefined) {
+            options[name] = defaults[name];
+        }
+    }
+
+
+    var filename = options.filename;
+
+
+    try {
+        
+        var Render = compiler(source, options);
+        
+    } catch (e) {
+    
+        e.filename = filename || 'anonymous';
+        e.name = 'Syntax Error';
+
+        return showDebugInfo(e);
+        
+    }
+    
+    
+    // 对编译结果进行一次包装
+
+    function render (data) {
+        
+        try {
+            
+            return new Render(data, filename) + '';
+            
+        } catch (e) {
+            
+            // 运行时出错后自动开启调试模式重新编译
+            if (!options.debug) {
+                options.debug = true;
+                return compile(source, options)(data);
+            }
+            
+            return showDebugInfo(e)();
+            
+        }
+        
+    }
+    
+
+    render.prototype = Render.prototype;
+    render.toString = function () {
+        return Render.toString();
+    };
+
+
+    if (filename && options.cache) {
+        cacheStore[filename] = render;
+    }
+
+    
+    return render;
+
+};
+
+
+
+
+// 数组迭代
+var forEach = utils.$each;
+
+
+// 静态分析模板变量
+var KEYWORDS =
+    // 关键字
+    'break,case,catch,continue,debugger,default,delete,do,else,false'
+    + ',finally,for,function,if,in,instanceof,new,null,return,switch,this'
+    + ',throw,true,try,typeof,var,void,while,with'
+
+    // 保留字
+    + ',abstract,boolean,byte,char,class,const,double,enum,export,extends'
+    + ',final,float,goto,implements,import,int,interface,long,native'
+    + ',package,private,protected,public,short,static,super,synchronized'
+    + ',throws,transient,volatile'
+
+    // ECMA 5 - use strict
+    + ',arguments,let,yield'
+
+    + ',undefined';
+
+var REMOVE_RE = /\/\*[\w\W]*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|"(?:[^"\\]|\\[\w\W])*"|'(?:[^'\\]|\\[\w\W])*'|\s*\.\s*[$\w\.]+/g;
+var SPLIT_RE = /[^\w$]+/g;
+var KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g');
+var NUMBER_RE = /^\d[^,]*|,\d[^,]*/g;
+var BOUNDARY_RE = /^,+|,+$/g;
+var SPLIT2_RE = /^$|,+/;
+
+
+// 获取变量
+function getVariable (code) {
+    return code
+    .replace(REMOVE_RE, '')
+    .replace(SPLIT_RE, ',')
+    .replace(KEYWORDS_RE, '')
+    .replace(NUMBER_RE, '')
+    .replace(BOUNDARY_RE, '')
+    .split(SPLIT2_RE);
+};
+
+
+// 字符串转义
+function stringify (code) {
+    return "'" + code
+    // 单引号与反斜杠转义
+    .replace(/('|\\)/g, '\\$1')
+    // 换行符转义(windows + linux)
+    .replace(/\r/g, '\\r')
+    .replace(/\n/g, '\\n') + "'";
+}
+
+
+function compiler (source, options) {
+    
+    var debug = options.debug;
+    var openTag = options.openTag;
+    var closeTag = options.closeTag;
+    var parser = options.parser;
+    var compress = options.compress;
+    var escape = options.escape;
+    
+
+    
+    var line = 1;
+    var uniq = {$data:1,$filename:1,$utils:1,$helpers:1,$out:1,$line:1};
+    
+
+
+    var isNewEngine = ''.trim;// '__proto__' in {}
+    var replaces = isNewEngine
+    ? ["$out='';", "$out+=", ";", "$out"]
+    : ["$out=[];", "$out.push(", ");", "$out.join('')"];
+
+    var concat = isNewEngine
+        ? "$out+=text;return $out;"
+        : "$out.push(text);";
+          
+    var print = "function(){"
+    +      "var text=''.concat.apply('',arguments);"
+    +       concat
+    +  "}";
+
+    var include = "function(filename,data){"
+    +      "data=data||$data;"
+    +      "var text=$utils.$include(filename,data,$filename);"
+    +       concat
+    +   "}";
+
+    var headerCode = "'use strict';"
+    + "var $utils=this,$helpers=$utils.$helpers,"
+    + (debug ? "$line=0," : "");
+    
+    var mainCode = replaces[0];
+
+    var footerCode = "return new String(" + replaces[3] + ");"
+    
+    // html与逻辑语法分离
+    forEach(source.split(openTag), function (code) {
+        code = code.split(closeTag);
+        
+        var $0 = code[0];
+        var $1 = code[1];
+        
+        // code: [html]
+        if (code.length === 1) {
+            
+            mainCode += html($0);
+         
+        // code: [logic, html]
+        } else {
+            
+            mainCode += logic($0);
+            
+            if ($1) {
+                mainCode += html($1);
+            }
+        }
+        
+
+    });
+    
+    var code = headerCode + mainCode + footerCode;
+    
+    // 调试语句
+    if (debug) {
+        code = "try{" + code + "}catch(e){"
+        +       "throw {"
+        +           "filename:$filename,"
+        +           "name:'Render Error',"
+        +           "message:e.message,"
+        +           "line:$line,"
+        +           "source:" + stringify(source)
+        +           ".split(/\\n/)[$line-1].replace(/^\\s+/,'')"
+        +       "};"
+        + "}";
+    }
+    
+    
+    
+    try {
+        
+        
+        var Render = new Function("$data", "$filename", code);
+        Render.prototype = utils;
+
+        return Render;
+        
+    } catch (e) {
+        e.temp = "function anonymous($data,$filename) {" + code + "}";
+        throw e;
+    }
+
+
+
+    
+    // 处理 HTML 语句
+    function html (code) {
+        
+        // 记录行号
+        line += code.split(/\n/).length - 1;
+
+        // 压缩多余空白与注释
+        if (compress) {
+            code = code
+            .replace(/\s+/g, ' ')
+            .replace(/<!--[\w\W]*?-->/g, '');
+        }
+        
+        if (code) {
+            code = replaces[1] + stringify(code) + replaces[2] + "\n";
+        }
+
+        return code;
+    }
+    
+    
+    // 处理逻辑语句
+    function logic (code) {
+
+        var thisLine = line;
+       
+        if (parser) {
+        
+             // 语法转换插件钩子
+            code = parser(code, options);
+            
+        } else if (debug) {
+        
+            // 记录行号
+            code = code.replace(/\n/g, function () {
+                line ++;
+                return "$line=" + line +  ";";
+            });
+            
+        }
+        
+        
+        // 输出语句. 编码: <%=value%> 不编码:<%=#value%>
+        // <%=#value%> 等同 v2.0.3 之前的 <%==value%>
+        if (code.indexOf('=') === 0) {
+
+            var escapeSyntax = escape && !/^=[=#]/.test(code);
+
+            code = code.replace(/^=[=#]?|[\s;]*$/g, '');
+
+            // 对内容编码
+            if (escapeSyntax) {
+
+                var name = code.replace(/\s*\([^\)]+\)/, '');
+
+                // 排除 utils.* | include | print
+                
+                if (!utils[name] && !/^(include|print)$/.test(name)) {
+                    code = "$escape(" + code + ")";
+                }
+
+            // 不编码
+            } else {
+                code = "$string(" + code + ")";
+            }
+            
+
+            code = replaces[1] + code + replaces[2];
+
+        }
+        
+        if (debug) {
+            code = "$line=" + thisLine + ";" + code;
+        }
+        
+        // 提取模板中的变量名
+        forEach(getVariable(code), function (name) {
+            
+            // name 值可能为空,在安卓低版本浏览器下
+            if (!name || uniq[name]) {
+                return;
+            }
+
+            var value;
+
+            // 声明模板变量
+            // 赋值优先级:
+            // [include, print] > utils > helpers > data
+            if (name === 'print') {
+
+                value = print;
+
+            } else if (name === 'include') {
+                
+                value = include;
+                
+            } else if (utils[name]) {
+
+                value = "$utils." + name;
+
+            } else if (helpers[name]) {
+
+                value = "$helpers." + name;
+
+            } else {
+
+                value = "$data." + name;
+            }
+            
+            headerCode += name + "=" + value + ",";
+            uniq[name] = true;
+            
+            
+        });
+        
+        return code + "\n";
+    }
+    
+    
+};
+
+
+
+// CommonJs
+if (typeof exports === 'object' && typeof module !== 'undefined') {
+    module.exports = template;
+// RequireJS && SeaJS
+} else if (typeof define === 'function') {
+    define(function() {
+        return template;
+    });
+} else {
+    this.template = template;
+}
+
+})();

File diff suppressed because it is too large
+ 1 - 0
public/assets/libs/art-template/dist/template-native.js


File diff suppressed because it is too large
+ 1 - 0
public/assets/libs/art-template/dist/template.js


+ 73 - 0
public/assets/libs/art-template/doc/syntax-native.md

@@ -0,0 +1,73 @@
+# artTemplate 原生 js 模板语法版
+
+## 使用
+
+在页面中引用模板引擎:
+
+    <script src="dist/template-native.js"></script>
+    
+[下载](https://raw.github.com/aui/artTemplate/master/dist/template-native.js)
+
+## 表达式
+
+``<%`` 与 ``%>`` 符号包裹起来的语句则为模板的逻辑表达式。
+
+### 输出表达式
+
+对内容编码输出:
+
+    <%=content%>
+
+不编码输出:
+
+    <%=#content%>
+    
+编码可以防止数据中含有 HTML 字符串,避免引起 XSS 攻击。
+
+### 逻辑
+
+支持使用 js 原生语法
+
+	<h1><%=title%></h1>
+	<ul>
+    	<%for(i = 0; i < list.length; i ++) {%>
+        	<li>条目内容 <%=i + 1%> :<%=list[i]%></li>
+    	<%}%>
+	</ul>
+	
+> 模板不能访问全局对象,公用的方法请参见文档[辅助方法](#辅助方法)章节
+
+### 模板包含表达式
+
+用于嵌入子模板。
+
+    <% include('template_name') %>
+
+子模板默认共享当前数据,亦可以指定数据:
+
+    <% include('template_name', news_list) %>
+
+## 辅助方法
+
+使用``template.helper(name, callback)``注册公用辅助方法:
+
+	template.helper('dateFormat', function (date, format) {
+    	// ..
+    	return value;
+	});
+
+模板中使用的方式:
+
+    <%=dateFormat(content) %>
+    
+##	演示例子
+
+*	[基本例子](http://aui.github.io/artTemplate/demo/template-native/basic.html)
+*	[不转义HTML](http://aui.github.io/artTemplate/demo/template-native/no-escape.html)
+*	[在javascript中存放模板](http://aui.github.io/artTemplate/demo/template-native/compile.html)
+*	[嵌入子模板(include)](http://aui.github.io/artTemplate/demo/template-native/include.html)
+*	[访问外部公用函数(辅助方法)](http://aui.github.io/artTemplate/demo/template-native/helper.html)
+
+----------------------------------------------
+
+本文档针对 artTemplate v3.0.0 编写

+ 90 - 0
public/assets/libs/art-template/doc/syntax-simple.md

@@ -0,0 +1,90 @@
+# artTemplate 简洁语法版
+
+## 使用
+
+引用简洁语法的引擎版本,例如:
+
+    <script src="dist/template.js"></script>
+    
+ [下载](https://raw.github.com/aui/artTemplate/master/dist/template.js)
+
+## 表达式
+
+``{{`` 与 ``}}`` 符号包裹起来的语句则为模板的逻辑表达式。
+
+### 输出表达式
+
+对内容编码输出:
+
+    {{content}}
+
+不编码输出:
+
+    {{#content}}
+    
+编码可以防止数据中含有 HTML 字符串,避免引起 XSS 攻击。
+
+### 条件表达式
+
+    {{if admin}}
+		<p>admin</p>
+    {{else if code > 0}}
+    	<p>master</p>
+    {{else}}
+        <p>error!</p>
+    {{/if}}
+
+### 遍历表达式
+
+无论数组或者对象都可以用 each 进行遍历。
+
+    {{each list as value index}}
+        <li>{{index}} - {{value.user}}</li>
+    {{/each}}
+
+亦可以被简写:
+
+    {{each list}}
+        <li>{{$index}} - {{$value.user}}</li>
+    {{/each}}
+
+### 模板包含表达式
+
+用于嵌入子模板。
+
+    {{include 'template_name'}}
+
+子模板默认共享当前数据,亦可以指定数据:
+
+    {{include 'template_name' news_list}}
+
+## 辅助方法
+
+使用``template.helper(name, callback)``注册公用辅助方法:
+
+```
+template.helper('dateFormat', function (date, format) {
+    // ..
+    return value;
+});
+```
+
+模板中使用的方式:
+
+    {{time | dateFormat:'yyyy-MM-dd hh:mm:ss'}}
+
+支持传入参数与嵌套使用:
+
+    {{time | say:'cd' | ubb | link}}
+    
+##	演示例子
+
+*	[基本例子](http://aui.github.io/artTemplate/demo/basic.html)
+*	[不转义HTML](http://aui.github.io/artTemplate/demo/no-escape.html)
+*	[在javascript中存放模板](http://aui.github.io/artTemplate/demo/compile.html)
+*	[嵌入子模板(include)](http://aui.github.io/artTemplate/demo/include.html)
+*	[访问外部公用函数(辅助方法)](http://aui.github.io/artTemplate/demo/helper.html)
+
+----------------------------------------------
+
+本文档针对 artTemplate v3.0.0+ 编写

+ 18 - 0
public/assets/libs/art-template/loader/index.js

@@ -0,0 +1,18 @@
+var template = require('art-template/dist/template');
+
+module.exports = function(source) {
+    this.cacheable && this.cacheable()
+
+    var ANONYMOUS_RE = /^function\s+anonymous/
+
+    template.onerror = function(e) {
+        var message = 'Template Error\n\n';
+        for (var name in e) {
+            message += '<' + name + '>\n' + e[name] + '\n\n';
+        }
+        throw new SyntaxError(message)
+    }
+
+    var render = template.compile(source, {}).toString().replace(ANONYMOUS_RE, 'function');
+    return 'module.exports = require("art-template/loader/runtime")(' + render + ');';
+}

+ 14 - 0
public/assets/libs/art-template/loader/package.json

@@ -0,0 +1,14 @@
+{
+  "name": "t-loader",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC",
+  "dependencies": {
+    "art-template": "^3.1.3"
+  }
+}

+ 129 - 0
public/assets/libs/art-template/loader/runtime.js

@@ -0,0 +1,129 @@
+function template(content) {
+    return compile(content);
+};
+
+var String = this.String;
+
+function toString(value, type) {
+
+    if (typeof value !== 'string') {
+
+        type = typeof value;
+        if (type === 'number') {
+            value += '';
+        } else if (type === 'function') {
+            value = toString(value.call(value));
+        } else {
+            value = '';
+        }
+    }
+
+    return value;
+
+};
+
+
+var escapeMap = {
+    "<": "&#60;",
+    ">": "&#62;",
+    '"': "&#34;",
+    "'": "&#39;",
+    "&": "&#38;"
+};
+
+
+function escapeFn(s) {
+    return escapeMap[s];
+}
+
+
+function escapeHTML(content) {
+    return toString(content)
+        .replace(/&(?![\w#]+;)|[<>"']/g, escapeFn);
+};
+
+
+var isArray = Array.isArray || function (obj) {
+    return ({}).toString.call(obj) === '[object Array]';
+};
+
+
+function each(data, callback) {
+    if (isArray(data)) {
+        for (var i = 0, len = data.length; i < len; i++) {
+            callback.call(data, data[i], i, data);
+        }
+    } else {
+        for (i in data) {
+            callback.call(data, data[i], i);
+        }
+    }
+};
+
+
+var utils = template.utils = {
+
+    $helpers: {},
+
+    $include: function () {
+        throw new Error('art-template/loader: not support `include`.');
+    },
+
+    $string: toString,
+
+    $escape: escapeHTML,
+
+    $each: each
+
+};
+
+
+var helpers = template.helpers = utils.$helpers;
+
+
+function compile(fn) {
+    var render = function (data) {
+        try {
+            return new fn(data) + '';
+        } catch (e) {
+            return showDebugInfo(e)();
+        }
+    };
+
+    render.prototype = fn.prototype = utils;
+    render.toString = function () {
+        return fn + '';
+    };
+
+    return render;
+};
+
+
+function showDebugInfo(e) {
+
+    var type = "{Template Error}";
+    var message = e.stack || '';
+
+    if (message) {
+        // 利用报错堆栈信息
+        message = message.split('\n').slice(0, 2).join('\n');
+    } else {
+        // 调试版本,直接给出模板语句行
+        for (var name in e) {
+            message += "<" + name + ">\n" + e[name] + "\n\n";
+        }
+    }
+
+    return function () {
+        if (typeof console === "object") {
+            console.error(type + "\n\n" + message);
+        }
+        return type;
+    };
+};
+
+template.helper = function (name, helper) {
+    helpers[name] = helper;
+};
+
+module.exports = template;

+ 90 - 0
public/assets/libs/art-template/node/_node.js

@@ -0,0 +1,90 @@
+var fs = require('fs');
+var path = require('path');
+
+module.exports = function (template) {
+
+	var cacheStore = template.cache;
+	var defaults = template.defaults;
+	var rExtname;
+
+	// 提供新的配置字段
+	defaults.base = '';
+	defaults.extname = '.html';
+	defaults.encoding = 'utf-8';
+
+	function compileFromFS(filename) {
+		// 加载模板并编译
+		var source = readTemplate(filename);
+
+		if (typeof source === 'string') {
+			return template.compile(source, {
+				filename: filename
+			});
+		}
+	}
+
+	// 重写引擎编译结果获取方法
+	template.get = function (filename) {
+		
+	    var fn;
+
+
+	    if (cacheStore.hasOwnProperty(filename)) {
+	        // 使用内存缓存
+	        fn = cacheStore[filename];
+	    } else {
+			fn = compileFromFS(filename);
+	    }
+
+	    return fn;
+	};
+
+	
+	function readTemplate (id) {
+	    id = path.join(defaults.base, id + defaults.extname);
+	    
+	    if (id.indexOf(defaults.base) !== 0) {
+	        // 安全限制:禁止超出模板目录之外调用文件
+	        throw new Error('"' + id + '" is not in the template directory');
+	    } else {
+	        try {
+	            return fs.readFileSync(id, defaults.encoding);
+	        } catch (e) {}
+	    }
+	}
+
+
+	// 重写模板`include``语句实现方法,转换模板为绝对路径
+	template.utils.$include = function (filename, data, from) {
+	    
+	    from = path.dirname(from);
+	    filename = path.join(from, filename);
+	    
+	    return template.renderFile(filename, data);
+	}
+
+
+	// express support
+	template.__express = function (file, options, fn) {
+
+	    if (typeof options === 'function') {
+	        fn = options;
+	        options = {};
+	    }
+
+
+		if (!rExtname) {
+			// 去掉 express 传入的路径
+			rExtname = new RegExp((defaults.extname + '$').replace(/\./g, '\\.'));
+		}
+
+
+	    file = file.replace(rExtname, '');
+
+	    options.filename = file;
+	    fn(null, template.renderFile(file, options));
+	};
+
+
+	return template;
+}

Some files were not shown because too many files changed in this diff