8
0
Просмотр исходного кода

First attempt to port src/*.js files.

Piotrek Koszuliński 10 лет назад
Родитель
Сommit
71d26d51f6
75 измененных файлов с 3138 добавлено и 3019 удалено
  1. 1 5
      packages/ckeditor5-ui/.jshintrc
  2. 12 3
      packages/ckeditor5-ui/gruntfile.js
  3. 1 1
      packages/ckeditor5-ui/package.json
  4. 27 31
      packages/ckeditor5-ui/src/ckeditorerror.js
  5. 213 213
      packages/ckeditor5-ui/src/collection.js
  6. 158 159
      packages/ckeditor5-ui/src/config.js
  7. 235 234
      packages/ckeditor5-ui/src/emittermixin.js
  8. 30 32
      packages/ckeditor5-ui/src/eventinfo.js
  9. 5 0
      packages/ckeditor5-ui/src/lib/lodash/array.js
  10. 28 0
      packages/ckeditor5-ui/src/lib/lodash/array/last.js
  11. 5 0
      packages/ckeditor5-ui/src/lib/lodash/function.js
  12. 58 0
      packages/ckeditor5-ui/src/lib/lodash/function/restParam.js
  13. 20 0
      packages/ckeditor5-ui/src/lib/lodash/internal/arrayCopy.js
  14. 22 0
      packages/ckeditor5-ui/src/lib/lodash/internal/arrayEach.js
  15. 23 0
      packages/ckeditor5-ui/src/lib/lodash/internal/arraySome.js
  16. 32 0
      packages/ckeditor5-ui/src/lib/lodash/internal/assignWith.js
  17. 19 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseAssign.js
  18. 128 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseClone.js
  19. 23 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseCopy.js
  20. 17 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseFor.js
  21. 17 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseForIn.js
  22. 17 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseForOwn.js
  23. 28 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseIsEqual.js
  24. 102 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseIsEqualDeep.js
  25. 14 0
      packages/ckeditor5-ui/src/lib/lodash/internal/baseProperty.js
  26. 39 0
      packages/ckeditor5-ui/src/lib/lodash/internal/bindCallback.js
  27. 22 0
      packages/ckeditor5-ui/src/lib/lodash/internal/bufferClone.js
  28. 41 0
      packages/ckeditor5-ui/src/lib/lodash/internal/createAssigner.js
  29. 27 0
      packages/ckeditor5-ui/src/lib/lodash/internal/createBaseFor.js
  30. 51 0
      packages/ckeditor5-ui/src/lib/lodash/internal/equalArrays.js
  31. 48 0
      packages/ckeditor5-ui/src/lib/lodash/internal/equalByTag.js
  32. 67 0
      packages/ckeditor5-ui/src/lib/lodash/internal/equalObjects.js
  33. 15 0
      packages/ckeditor5-ui/src/lib/lodash/internal/getLength.js
  34. 16 0
      packages/ckeditor5-ui/src/lib/lodash/internal/getNative.js
  35. 26 0
      packages/ckeditor5-ui/src/lib/lodash/internal/initCloneArray.js
  36. 63 0
      packages/ckeditor5-ui/src/lib/lodash/internal/initCloneByTag.js
  37. 16 0
      packages/ckeditor5-ui/src/lib/lodash/internal/initCloneObject.js
  38. 15 0
      packages/ckeditor5-ui/src/lib/lodash/internal/isArrayLike.js
  39. 24 0
      packages/ckeditor5-ui/src/lib/lodash/internal/isIndex.js
  40. 28 0
      packages/ckeditor5-ui/src/lib/lodash/internal/isIterateeCall.js
  41. 20 0
      packages/ckeditor5-ui/src/lib/lodash/internal/isLength.js
  42. 12 0
      packages/ckeditor5-ui/src/lib/lodash/internal/isObjectLike.js
  43. 30 0
      packages/ckeditor5-ui/src/lib/lodash/internal/root.js
  44. 41 0
      packages/ckeditor5-ui/src/lib/lodash/internal/shimKeys.js
  45. 14 0
      packages/ckeditor5-ui/src/lib/lodash/internal/toObject.js
  46. 23 0
      packages/ckeditor5-ui/src/lib/lodash/lang.js
  47. 78 0
      packages/ckeditor5-ui/src/lib/lodash/lang/clone.js
  48. 2 0
      packages/ckeditor5-ui/src/lib/lodash/lang/eq.js
  49. 34 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isArguments.js
  50. 48 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isArray.js
  51. 62 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isEqual.js
  52. 38 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isFunction.js
  53. 48 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isNative.js
  54. 37 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isObject.js
  55. 79 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isPlainObject.js
  56. 74 0
      packages/ckeditor5-ui/src/lib/lodash/lang/isTypedArray.js
  57. 0 1650
      packages/ckeditor5-ui/src/lib/lodash/lodash-ckeditor.js
  58. 11 0
      packages/ckeditor5-ui/src/lib/lodash/object.js
  59. 51 0
      packages/ckeditor5-ui/src/lib/lodash/object/assign.js
  60. 2 0
      packages/ckeditor5-ui/src/lib/lodash/object/extend.js
  61. 45 0
      packages/ckeditor5-ui/src/lib/lodash/object/keys.js
  62. 64 0
      packages/ckeditor5-ui/src/lib/lodash/object/keysIn.js
  63. 5 0
      packages/ckeditor5-ui/src/lib/lodash/utility.js
  64. 20 0
      packages/ckeditor5-ui/src/lib/lodash/utility/identity.js
  65. 29 31
      packages/ckeditor5-ui/src/log.js
  66. 420 419
      packages/ckeditor5-ui/src/model.js
  67. 0 86
      packages/ckeditor5-ui/src/utils-lodash.js
  68. 103 121
      packages/ckeditor5-ui/src/utils.js
  69. 9 28
      packages/ckeditor5-ui/tests/model.js
  70. 1 1
      packages/ckeditor5-ui/tests/ui/controller.js
  71. 1 1
      packages/ckeditor5-ui/tests/ui/controllercollection.js
  72. 1 1
      packages/ckeditor5-ui/tests/ui/domemittermixin.js
  73. 1 1
      packages/ckeditor5-ui/tests/ui/region.js
  74. 1 1
      packages/ckeditor5-ui/tests/ui/template.js
  75. 1 1
      packages/ckeditor5-ui/tests/ui/view.js

+ 1 - 5
packages/ckeditor5-ui/.jshintrc

@@ -11,9 +11,5 @@
 	"strict": true,
 	"varstmt": true,
 
-	"globalstrict": true,
-
-	"globals": {
-		"CKEDITOR": false
-	}
+	"globalstrict": true
 }

+ 12 - 3
packages/ckeditor5-ui/gruntfile.js

@@ -18,14 +18,23 @@ module.exports = ( grunt ) => {
 
 		lodash: {
 			build: {
-				dest: 'src/lib/lodash/lodash-ckeditor.js',
+				dest: 'src/lib/lodash',
 				options: {
 					modifier: 'modern',
-					exports: 'amd',
+					modularize: true,
+					exports: 'es',
 					flags: [
 						'development'
 					],
-					include: require( './src/utils-lodash' )
+					include: [
+						'clone',
+						'extend',
+						'isPlainObject',
+						'isObject',
+						'isArray',
+						'last',
+						'isEqual'
+					]
 				}
 			}
 		},

+ 1 - 1
packages/ckeditor5-ui/package.json

@@ -13,7 +13,7 @@
     "grunt-githooks": "^0",
     "shelljs": "^0",
     "lodash-cli": "^3",
-    "grunt-lodash": "^0.4.0"
+    "grunt-lodash": "^0.5.0"
   },
   "author": "CKSource (http://cksource.com/)",
   "license": "See LICENSE.md",

+ 27 - 31
packages/ckeditor5-ui/src/ckeditorerror.js

@@ -17,38 +17,34 @@
  * @extends Error
  */
 
-CKEDITOR.define( () => {
-	class CKEditorError extends Error {
-		/**
-		 * Creates an instance of the CKEditorError class.
-		 *
-		 * Read more about error logging in the {@link core.log} module.
-		 *
-		 * @constructor
-		 * @param {String} message The error message in an `error-name: Error message.` format.
-		 * During the minification process the "Error message" part will be removed to limit the code size
-		 * and a link to this error documentation will be added to the `message`.
-		 * @param {Object} [data] Additional data describing the error. A stringified version of this object
-		 * will be appended to the error {@link #message}, so the data are quickly visible in the console. The original
-		 * data object will also be later available under the {@link #data} property.
-		 */
-		constructor( message, data ) {
-			if ( data ) {
-				message += ' ' + JSON.stringify( data );
-			}
+export default class CKEditorError extends Error {
+	/**
+	 * Creates an instance of the CKEditorError class.
+	 *
+	 * Read more about error logging in the {@link core.log} module.
+	 *
+	 * @constructor
+	 * @param {String} message The error message in an `error-name: Error message.` format.
+	 * During the minification process the "Error message" part will be removed to limit the code size
+	 * and a link to this error documentation will be added to the `message`.
+	 * @param {Object} [data] Additional data describing the error. A stringified version of this object
+	 * will be appended to the error {@link #message}, so the data are quickly visible in the console. The original
+	 * data object will also be later available under the {@link #data} property.
+	 */
+	constructor( message, data ) {
+		if ( data ) {
+			message += ' ' + JSON.stringify( data );
+		}
 
-			super( message );
+		super( message );
 
-			this.name = 'CKEditorError';
+		this.name = 'CKEditorError';
 
-			/**
-			 * The additional error data passed to the constructor.
-			 *
-			 * @property {Object} data
-			 */
-			this.data = data;
-		}
+		/**
+		 * The additional error data passed to the constructor.
+		 *
+		 * @property {Object} data
+		 */
+		this.data = data;
 	}
-
-	return CKEditorError;
-} );
+}

+ 213 - 213
packages/ckeditor5-ui/src/collection.js

@@ -19,261 +19,261 @@
  * @mixins EventEmitter
  */
 
-CKEDITOR.define( [ 'emittermixin', 'ckeditorerror', 'utils' ], ( EmitterMixin, CKEditorError, utils ) => {
-	class Collection {
+import EmitterMixin from './emittermixin.js';
+import CKEditorError from './ckeditorerror.js';
+import utilsObject from './lib/lodash/object.js';
+
+export default class Collection {
+	/**
+	 * Creates a new Collection instance.
+	 *
+	 * @constructor
+	 * @param {Iterale} [items] Items to be added to the collection.
+	 * @param {Object} options The options object.
+	 * @param {String} [options.idProperty='id'] The name of the property which is considered to identify an item.
+	 */
+	constructor( options ) {
 		/**
-		 * Creates a new Collection instance.
+		 * The internal list of items in the collection.
 		 *
-		 * @constructor
-		 * @param {Iterale} [items] Items to be added to the collection.
-		 * @param {Object} options The options object.
-		 * @param {String} [options.idProperty='id'] The name of the property which is considered to identify an item.
+		 * @private
+		 * @property {Object[]}
 		 */
-		constructor( options ) {
-			/**
-			 * The internal list of items in the collection.
-			 *
-			 * @private
-			 * @property {Object[]}
-			 */
-			this._items = [];
-
-			/**
-			 * The internal map of items in the collection.
-			 *
-			 * @private
-			 * @property {Map}
-			 */
-			this._itemMap = new Map();
-
-			/**
-			 * Next id which will be assigned to unidentified item while adding it to the collection.
-			 *
-			 * @private
-			 * @property
-			 */
-			this._nextId = 0;
-
-			/**
-			 * The name of the property which is considered to identify an item.
-			 *
-			 * @private
-			 * @property {String}
-			 */
-			this._idProperty = options && options.idProperty || 'id';
-		}
+		this._items = [];
 
 		/**
-		 * The number of items available in the collection.
+		 * The internal map of items in the collection.
 		 *
-		 * @property length
+		 * @private
+		 * @property {Map}
 		 */
-		get length() {
-			return this._items.length;
-		}
+		this._itemMap = new Map();
 
 		/**
-		 * Adds an item into the collection.
+		 * Next id which will be assigned to unidentified item while adding it to the collection.
 		 *
-		 * If the item does not have an id, then it will be automatically generated and set on the item.
+		 * @private
+		 * @property
+		 */
+		this._nextId = 0;
+
+		/**
+		 * The name of the property which is considered to identify an item.
 		 *
-		 * @chainable
-		 * @param {Object} item
-		 * @param {Number} [index] The position of the item in the collection. The item
-		 * is pushed to the collection when `index` not specified.
+		 * @private
+		 * @property {String}
 		 */
-		add( item, index ) {
-			let itemId;
-			const idProperty = this._idProperty;
-
-			if ( ( idProperty in item ) ) {
-				itemId = item[ idProperty ];
-
-				if ( typeof itemId != 'string' ) {
-					/**
-					 * This item's id should be a string.
-					 *
-					 * @error collection-add-invalid-id
-					 */
-					throw new CKEditorError( 'collection-add-invalid-id' );
-				}
-
-				if ( this.get( itemId ) ) {
-					/**
-					 * This item already exists in the collection.
-					 *
-					 * @error collection-add-item-already-exists
-					 */
-					throw new CKEditorError( 'collection-add-item-already-exists' );
-				}
-			} else {
-				itemId = this._getNextId();
-				item[ idProperty ] = itemId;
-			}
+		this._idProperty = options && options.idProperty || 'id';
+	}
 
-			// TODO: Use ES6 default function argument.
-			if ( index === undefined ) {
-				index = this._items.length;
-			} else if ( index > this._items.length || index < 0 ) {
+	/**
+	 * The number of items available in the collection.
+	 *
+	 * @property length
+	 */
+	get length() {
+		return this._items.length;
+	}
+
+	/**
+	 * Adds an item into the collection.
+	 *
+	 * If the item does not have an id, then it will be automatically generated and set on the item.
+	 *
+	 * @chainable
+	 * @param {Object} item
+	 * @param {Number} [index] The position of the item in the collection. The item
+	 * is pushed to the collection when `index` not specified.
+	 */
+	add( item, index ) {
+		let itemId;
+		const idProperty = this._idProperty;
+
+		if ( ( idProperty in item ) ) {
+			itemId = item[ idProperty ];
+
+			if ( typeof itemId != 'string' ) {
 				/**
-				 * The index number has invalid value.
+				 * This item's id should be a string.
 				 *
-				 * @error collection-add-item-bad-index
+				 * @error collection-add-invalid-id
 				 */
-				throw new CKEditorError( 'collection-add-item-invalid-index' );
+				throw new CKEditorError( 'collection-add-invalid-id' );
 			}
 
-			this._items.splice( index, 0, item );
-
-			this._itemMap.set( itemId, item );
-
-			this.fire( 'add', item, index );
-
-			return this;
-		}
-
-		/**
-		 * Gets item by its id or index.
-		 *
-		 * @param {String|Number} idOrIndex The item id or index in the collection.
-		 * @returns {Object} The requested item or `null` if such item does not exist.
-		 */
-		get( idOrIndex ) {
-			let item;
-
-			if ( typeof idOrIndex == 'string' ) {
-				item = this._itemMap.get( idOrIndex );
-			} else if ( typeof idOrIndex == 'number' ) {
-				item = this._items[ idOrIndex ];
-			} else {
+			if ( this.get( itemId ) ) {
 				/**
-				 * Index or id must be given.
+				 * This item already exists in the collection.
 				 *
-				 * @error collection-get-invalid-arg
+				 * @error collection-add-item-already-exists
 				 */
-				throw new CKEditorError( 'collection-get-invalid-arg: Index or id must be given.' );
+				throw new CKEditorError( 'collection-add-item-already-exists' );
 			}
+		} else {
+			itemId = this._getNextId();
+			item[ idProperty ] = itemId;
+		}
 
-			return item || null;
+		// TODO: Use ES6 default function argument.
+		if ( index === undefined ) {
+			index = this._items.length;
+		} else if ( index > this._items.length || index < 0 ) {
+			/**
+			 * The index number has invalid value.
+			 *
+			 * @error collection-add-item-bad-index
+			 */
+			throw new CKEditorError( 'collection-add-item-invalid-index' );
 		}
 
-		/**
-		 * Removes an item from the collection.
-		 *
-		 * @param {Object|Number|String} subject The item to remove, its id or index in the collection.
-		 * @returns {Object} The removed item.
-		 */
-		remove( subject ) {
-			let index, id, item;
-			let itemDoesNotExist = false;
-			const idProperty = this._idProperty;
-
-			if ( typeof subject == 'string' ) {
-				id = subject;
-				item = this._itemMap.get( id );
-				itemDoesNotExist = !item;
-
-				if ( item ) {
-					index = this._items.indexOf( item );
-				}
-			} else if ( typeof subject == 'number' ) {
-				index = subject;
-				item = this._items[ index ];
-				itemDoesNotExist = !item;
-
-				if ( item ) {
-					id = item[ idProperty ];
-				}
-			} else {
-				item = subject;
-				id = item[ idProperty ];
-				index = this._items.indexOf( item );
-				itemDoesNotExist = ( index == -1 || !this._itemMap.get( id ) );
-			}
+		this._items.splice( index, 0, item );
 
-			if ( itemDoesNotExist ) {
-				/**
-				 * Item not found.
-				 *
-				 * @error collection-remove-404
-				 */
-				throw new CKEditorError( 'collection-remove-404: Item not found.' );
-			}
+		this._itemMap.set( itemId, item );
 
-			this._items.splice( index, 1 );
-			this._itemMap.delete( id );
+		this.fire( 'add', item, index );
 
-			this.fire( 'remove', item );
+		return this;
+	}
 
-			return item;
+	/**
+	 * Gets item by its id or index.
+	 *
+	 * @param {String|Number} idOrIndex The item id or index in the collection.
+	 * @returns {Object} The requested item or `null` if such item does not exist.
+	 */
+	get( idOrIndex ) {
+		let item;
+
+		if ( typeof idOrIndex == 'string' ) {
+			item = this._itemMap.get( idOrIndex );
+		} else if ( typeof idOrIndex == 'number' ) {
+			item = this._items[ idOrIndex ];
+		} else {
+			/**
+			 * Index or id must be given.
+			 *
+			 * @error collection-get-invalid-arg
+			 */
+			throw new CKEditorError( 'collection-get-invalid-arg: Index or id must be given.' );
 		}
 
-		/**
-		 * Executes the callback for each item in the collection and composes an array or values returned by this callback.
-		 *
-		 * @param {Function} callback
-		 * @param {Item} callback.item
-		 * @param {Number} callback.index
-		 * @params {Object} ctx Context in which the `callback` will be called.
-		 * @returns {Array} The result of mapping.
-		 */
-		map( callback, ctx ) {
-			return this._items.map( callback, ctx );
-		}
+		return item || null;
+	}
 
-		/**
-		 * Finds the first item in the collection for which the `callback` returns a true value.
-		 *
-		 * @param {Function} callback
-		 * @param {Object} callback.item
-		 * @param {Number} callback.index
-		 * @returns {Object} The item for which `callback` returned a true value.
-		 * @params {Object} ctx Context in which the `callback` will be called.
-		 */
-		find( callback, ctx ) {
-			return this._items.find( callback, ctx );
-		}
+	/**
+	 * Removes an item from the collection.
+	 *
+	 * @param {Object|Number|String} subject The item to remove, its id or index in the collection.
+	 * @returns {Object} The removed item.
+	 */
+	remove( subject ) {
+		let index, id, item;
+		let itemDoesNotExist = false;
+		const idProperty = this._idProperty;
+
+		if ( typeof subject == 'string' ) {
+			id = subject;
+			item = this._itemMap.get( id );
+			itemDoesNotExist = !item;
+
+			if ( item ) {
+				index = this._items.indexOf( item );
+			}
+		} else if ( typeof subject == 'number' ) {
+			index = subject;
+			item = this._items[ index ];
+			itemDoesNotExist = !item;
 
-		/**
-		 * Returns an array with items for which the `callback` returned a true value.
-		 *
-		 * @param {Function} callback
-		 * @param {Object} callback.item
-		 * @param {Number} callback.index
-		 * @params {Object} ctx Context in which the `callback` will be called.
-		 * @returns {Object[]} The array with matching items.
-		 */
-		filter( callback, ctx ) {
-			return this._items.filter( callback, ctx );
+			if ( item ) {
+				id = item[ idProperty ];
+			}
+		} else {
+			item = subject;
+			id = item[ idProperty ];
+			index = this._items.indexOf( item );
+			itemDoesNotExist = ( index == -1 || !this._itemMap.get( id ) );
 		}
 
-		/**
-		 * Collection iterator.
-		 */
-		[ Symbol.iterator ]() {
-			return this._items[ Symbol.iterator ]();
+		if ( itemDoesNotExist ) {
+			/**
+			 * Item not found.
+			 *
+			 * @error collection-remove-404
+			 */
+			throw new CKEditorError( 'collection-remove-404: Item not found.' );
 		}
 
-		/**
-		 * Generates next (not yet used) id for unidentified item being add to the collection.
-		 *
-		 * @returns {String} The next id.
-		 */
-		_getNextId() {
-			let id;
+		this._items.splice( index, 1 );
+		this._itemMap.delete( id );
 
-			do {
-				id = String( this._nextId++ );
-			} while ( this._itemMap.has( id ) );
+		this.fire( 'remove', item );
 
-			return id;
-		}
+		return item;
 	}
 
-	utils.extend( Collection.prototype, EmitterMixin );
+	/**
+	 * Executes the callback for each item in the collection and composes an array or values returned by this callback.
+	 *
+	 * @param {Function} callback
+	 * @param {Item} callback.item
+	 * @param {Number} callback.index
+	 * @params {Object} ctx Context in which the `callback` will be called.
+	 * @returns {Array} The result of mapping.
+	 */
+	map( callback, ctx ) {
+		return this._items.map( callback, ctx );
+	}
+
+	/**
+	 * Finds the first item in the collection for which the `callback` returns a true value.
+	 *
+	 * @param {Function} callback
+	 * @param {Object} callback.item
+	 * @param {Number} callback.index
+	 * @returns {Object} The item for which `callback` returned a true value.
+	 * @params {Object} ctx Context in which the `callback` will be called.
+	 */
+	find( callback, ctx ) {
+		return this._items.find( callback, ctx );
+	}
+
+	/**
+	 * Returns an array with items for which the `callback` returned a true value.
+	 *
+	 * @param {Function} callback
+	 * @param {Object} callback.item
+	 * @param {Number} callback.index
+	 * @params {Object} ctx Context in which the `callback` will be called.
+	 * @returns {Object[]} The array with matching items.
+	 */
+	filter( callback, ctx ) {
+		return this._items.filter( callback, ctx );
+	}
+
+	/**
+	 * Collection iterator.
+	 */
+	[ Symbol.iterator ]() {
+		return this._items[ Symbol.iterator ]();
+	}
+
+	/**
+	 * Generates next (not yet used) id for unidentified item being add to the collection.
+	 *
+	 * @returns {String} The next id.
+	 */
+	_getNextId() {
+		let id;
+
+		do {
+			id = String( this._nextId++ );
+		} while ( this._itemMap.has( id ) );
+
+		return id;
+	}
+}
 
-	return Collection;
-} );
+utilsObject.extend( Collection.prototype, EmitterMixin );
 
 /**
  * Fired when an item is added to the collection.

+ 158 - 159
packages/ckeditor5-ui/src/config.js

@@ -12,186 +12,185 @@
  * @extends Model
  */
 
-CKEDITOR.define( [ 'model', 'utils' ], ( Model, utils ) => {
-	class Config extends Model {
-		/**
-		 * Creates an instance of the {@link Config} class.
-		 *
-		 * @param {Object} [configurations] The initial configurations to be set.
-		 * @constructor
-		 */
-		constructor( configurations ) {
-			super();
-
-			if ( configurations ) {
-				this.set( configurations );
-			}
+import Model from './model.js';
+import utilsLang from './lib/lodash/lang.js';
+
+export default class Config extends Model {
+	/**
+	 * Creates an instance of the {@link Config} class.
+	 *
+	 * @param {Object} [configurations] The initial configurations to be set.
+	 * @constructor
+	 */
+	constructor( configurations ) {
+		super();
+
+		if ( configurations ) {
+			this.set( configurations );
 		}
+	}
 
-		/**
-		 * Set configuration values.
-		 *
-		 * It accepts both a name/value pair or an object, which properties and values will be used to set
-		 * configurations.
-		 *
-		 * It also accepts setting a "deep configuration" by using dots in the name. For example, `'resize.width'` sets
-		 * the value for the `width` configuration in the `resize` subset.
-		 *
-		 *     config.set( 'width', 500 );
-		 *     config.set( 'toolbar.collapsed', true );
-		 *
-		 *     // Equivalent to:
-		 *     config.set( {
-		 *         width: 500
-		 *         toolbar: {
-		 *             collapsed: true
-		 *         }
-		 *     } );
-		 *
-		 * Passing an object as the value will amend the configuration, not replace it.
-		 *
-		 *     config.set( 'toolbar', {
-		 *         collapsed: true,
-		 *     } );
-		 *
-		 *     config.set( 'toolbar', {
-		 *         color: 'red',
-		 *     } );
-		 *
-		 *     config.toolbar.collapsed; // true
-		 *     config.toolbar.color; // 'red'
-		 *
-		 * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
-		 * configuration entries. Configuration names are case-insensitive.
-		 * @param {*} [value=null] The configuration value. Used if a name is passed to nameOrConfigurations.
-		 */
-		set( name, value ) {
-			// Just pass the call to the original set() in case of an object. It'll deal with recursing through the
-			// object and calling set( name, value ) again for each property.
-			if ( utils.isObject( name ) ) {
-				super.set.apply( this, arguments );
-
-				return;
-			}
-
-			// The target for this configuration is, for now, this object.
-			//jscs:disable safeContextKeyword
-			let target = this;
-			//jscs:enable
+	/**
+	 * Set configuration values.
+	 *
+	 * It accepts both a name/value pair or an object, which properties and values will be used to set
+	 * configurations.
+	 *
+	 * It also accepts setting a "deep configuration" by using dots in the name. For example, `'resize.width'` sets
+	 * the value for the `width` configuration in the `resize` subset.
+	 *
+	 *     config.set( 'width', 500 );
+	 *     config.set( 'toolbar.collapsed', true );
+	 *
+	 *     // Equivalent to:
+	 *     config.set( {
+	 *         width: 500
+	 *         toolbar: {
+	 *             collapsed: true
+	 *         }
+	 *     } );
+	 *
+	 * Passing an object as the value will amend the configuration, not replace it.
+	 *
+	 *     config.set( 'toolbar', {
+	 *         collapsed: true,
+	 *     } );
+	 *
+	 *     config.set( 'toolbar', {
+	 *         color: 'red',
+	 *     } );
+	 *
+	 *     config.toolbar.collapsed; // true
+	 *     config.toolbar.color; // 'red'
+	 *
+	 * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
+	 * configuration entries. Configuration names are case-insensitive.
+	 * @param {*} [value=null] The configuration value. Used if a name is passed to nameOrConfigurations.
+	 */
+	set( name, value ) {
+		// Just pass the call to the original set() in case of an object. It'll deal with recursing through the
+		// object and calling set( name, value ) again for each property.
+		if ( utilsLang.isObject( name ) ) {
+			super.set.apply( this, arguments );
+
+			return;
+		}
 
-			// The configuration name should be split into parts if it has dots. E.g: `resize.width`.
-			const parts = name.toLowerCase().split( '.' );
+		// The target for this configuration is, for now, this object.
+		//jscs:disable safeContextKeyword
+		let target = this;
+		//jscs:enable
 
-			// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`
-			name = parts.pop();
+		// The configuration name should be split into parts if it has dots. E.g: `resize.width`.
+		const parts = name.toLowerCase().split( '.' );
 
-			// Retrieves the final target for this configuration recursively.
-			for ( let i = 0; i < parts.length; i++ ) {
-				// The target will always be an instance of Config.
-				if ( !( target[ parts[ i ] ] instanceof Config ) ) {
-					target.set( parts[ i ], new Config() );
-				}
+		// Take the name of the configuration out of the parts. E.g. `resize.width` -> `width`
+		name = parts.pop();
 
-				target = target[ parts[ i ] ];
+		// Retrieves the final target for this configuration recursively.
+		for ( let i = 0; i < parts.length; i++ ) {
+			// The target will always be an instance of Config.
+			if ( !( target[ parts[ i ] ] instanceof Config ) ) {
+				target.set( parts[ i ], new Config() );
 			}
 
-			// Values set as pure objects will be treated as Config subsets.
-			if ( utils.isPlainObject( value ) ) {
-				// If the target is an instance of Config (a deep config subset).
-				if ( target[ name ] instanceof Config ) {
-					// Amend the target with the value, instead of replacing it.
-					target[ name ].set( value );
+			target = target[ parts[ i ] ];
+		}
 
-					return;
-				}
+		// Values set as pure objects will be treated as Config subsets.
+		if ( utilsLang.isPlainObject( value ) ) {
+			// If the target is an instance of Config (a deep config subset).
+			if ( target[ name ] instanceof Config ) {
+				// Amend the target with the value, instead of replacing it.
+				target[ name ].set( value );
 
-				value = new Config( value );
+				return;
 			}
 
-			// Values will never be undefined.
-			if ( typeof value == 'undefined' ) {
-				value = null;
-			}
+			value = new Config( value );
+		}
 
-			// Call the original set() on the target.
-			super.set.call( target, name, value );
+		// Values will never be undefined.
+		if ( typeof value == 'undefined' ) {
+			value = null;
 		}
 
-		/**
-		 * Gets the value for a configuration entry.
-		 *
-		 *     config.get( 'name' );
-		 *
-		 * Deep configurations can be retrieved by separating each part with a dot.
-		 *
-		 *     config.get( 'toolbar.collapsed' );
-		 *
-		 * @param {String} name The configuration name. Configuration names are case-insensitive.
-		 * @returns {*} The configuration value or `undefined` if the configuration entry was not found.
-		 */
-		get( name ) {
-			// The target for this configuration is, for now, this object.
-			//jscs:disable safeContextKeyword
-			let source = this;
-			//jscs:enable
-
-			// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`]
-			const parts = name.toLowerCase().split( '.' );
-
-			// Take the name of the configuration from the parts. E.g. `resize.width` -> `width`
-			name = parts.pop();
-
-			// Retrieves the source for this configuration recursively.
-			for ( let i = 0; i < parts.length; i++ ) {
-				// The target will always be an instance of Config.
-				if ( !( source[ parts[ i ] ] instanceof Config ) ) {
-					source = null;
-					break;
-				}
-
-				source = source[ parts[ i ] ];
-			}
+		// Call the original set() on the target.
+		super.set.call( target, name, value );
+	}
 
-			// Try to retrieve it from the source object.
-			if ( source && ( typeof source[ name ] != 'undefined' ) ) {
-				return source[ name ];
+	/**
+	 * Gets the value for a configuration entry.
+	 *
+	 *     config.get( 'name' );
+	 *
+	 * Deep configurations can be retrieved by separating each part with a dot.
+	 *
+	 *     config.get( 'toolbar.collapsed' );
+	 *
+	 * @param {String} name The configuration name. Configuration names are case-insensitive.
+	 * @returns {*} The configuration value or `undefined` if the configuration entry was not found.
+	 */
+	get( name ) {
+		// The target for this configuration is, for now, this object.
+		//jscs:disable safeContextKeyword
+		let source = this;
+		//jscs:enable
+
+		// The configuration name should be split into parts if it has dots. E.g. `resize.width` -> [`resize`, `width`]
+		const parts = name.toLowerCase().split( '.' );
+
+		// Take the name of the configuration from the parts. E.g. `resize.width` -> `width`
+		name = parts.pop();
+
+		// Retrieves the source for this configuration recursively.
+		for ( let i = 0; i < parts.length; i++ ) {
+			// The target will always be an instance of Config.
+			if ( !( source[ parts[ i ] ] instanceof Config ) ) {
+				source = null;
+				break;
 			}
 
-			// If not found, take it from the definition.
-			if ( this.definition ) {
-				return this.definition[ name ];
-			}
+			source = source[ parts[ i ] ];
 		}
 
-		/**
-		 * Defines the name and default value for configurations. It accepts the same parameters as the
-		 * {@link Config#set set()} method.
-		 *
-		 * On first call, the {@link Config#definition definition} property is created to hold all defined
-		 * configurations.
-		 *
-		 * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be
-		 * rarely used for other needs.
-		 *
-		 * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
-		 * configuration entries.
-		 * @param {*} [value] The configuration value. Used if a name is passed to nameOrConfigurations. If undefined,
-		 * the configuration is set to `null`.
-		 */
-		define( name, value ) {
-			if ( !this.definition ) {
-				/**
-				 * TODO
-				 *
-				 * @property
-				 * @type {Config}
-				 */
-				this.definition = new Config();
-			}
+		// Try to retrieve it from the source object.
+		if ( source && ( typeof source[ name ] != 'undefined' ) ) {
+			return source[ name ];
+		}
 
-			this.definition.set( name, value );
+		// If not found, take it from the definition.
+		if ( this.definition ) {
+			return this.definition[ name ];
 		}
 	}
 
-	return Config;
-} );
+	/**
+	 * Defines the name and default value for configurations. It accepts the same parameters as the
+	 * {@link Config#set set()} method.
+	 *
+	 * On first call, the {@link Config#definition definition} property is created to hold all defined
+	 * configurations.
+	 *
+	 * This method is supposed to be called by plugin developers to setup plugin's configurations. It would be
+	 * rarely used for other needs.
+	 *
+	 * @param {String|Object} nameOrConfigurations The configuration name or an object from which take properties as
+	 * configuration entries.
+	 * @param {*} [value] The configuration value. Used if a name is passed to nameOrConfigurations. If undefined,
+	 * the configuration is set to `null`.
+	 */
+	define( name, value ) {
+		if ( !this.definition ) {
+			/**
+			 * TODO
+			 *
+			 * @property
+			 * @type {Config}
+			 */
+			this.definition = new Config();
+		}
+
+		this.definition.set( name, value );
+	}
+}

+ 235 - 234
packages/ckeditor5-ui/src/emittermixin.js

@@ -12,273 +12,274 @@
  * @singleton
  */
 
-CKEDITOR.define( [ 'eventinfo', 'utils' ], ( EventInfo, utils ) => {
-	const EmitterMixin = {
-		/**
-		 * Registers a callback function to be executed when an event is fired.
-		 *
-		 * @param {String} event The name of the event.
-		 * @param {Function} callback The function to be called on event.
-		 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to the object firing the
-		 * event.
-		 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
-		 * Lower values are called first.
-		 */
-		on( event, callback, ctx, priority ) {
-			const callbacks = getCallbacks( this, event );
-
-			// Set the priority defaults.
-			if ( typeof priority != 'number' ) {
-				priority = 10;
-			}
+import EventInfo from './eventinfo.js';
+import { uid } from './utils.js';
+
+const EmitterMixin = {
+	/**
+	 * Registers a callback function to be executed when an event is fired.
+	 *
+	 * @param {String} event The name of the event.
+	 * @param {Function} callback The function to be called on event.
+	 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to the object firing the
+	 * event.
+	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
+	 * Lower values are called first.
+	 */
+	on( event, callback, ctx, priority ) {
+		const callbacks = getCallbacks( this, event );
+
+		// Set the priority defaults.
+		if ( typeof priority != 'number' ) {
+			priority = 10;
+		}
 
-			callback = {
-				callback: callback,
-				ctx: ctx || this,
-				priority: priority
-			};
+		callback = {
+			callback: callback,
+			ctx: ctx || this,
+			priority: priority
+		};
 
-			// Add the callback to the list in the right priority position.
-			for ( let i = callbacks.length - 1; i >= 0; i-- ) {
-				if ( callbacks[ i ].priority <= priority ) {
-					callbacks.splice( i + 1, 0, callback );
+		// Add the callback to the list in the right priority position.
+		for ( let i = callbacks.length - 1; i >= 0; i-- ) {
+			if ( callbacks[ i ].priority <= priority ) {
+				callbacks.splice( i + 1, 0, callback );
 
-					return;
-				}
-			}
-
-			callbacks.unshift( callback );
-		},
-
-		/**
-		 * Registers a callback function to be executed on the next time the event is fired only. This is similar to
-		 * calling {@link #on} followed by {@link #off} in the callback.
-		 *
-		 * @param {String} event The name of the event.
-		 * @param {Function} callback The function to be called on event.
-		 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to the object firing the
-		 * event.
-		 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
-		 * Lower values are called first.
-		 */
-		once( event, callback, ctx, priority ) {
-			const onceCallback = function( event ) {
-				// Go off() at the first call.
-				event.off();
-
-				// Go with the original callback.
-				callback.apply( this, arguments );
-			};
-
-			// Make the a similar on() call, simply replacing the callback.
-			this.on( event, onceCallback, ctx, priority );
-		},
-
-		/**
-		 * Stops executing the callback on the given event.
-		 *
-		 * @param {String} event The name of the event.
-		 * @param {Function} callback The function to stop being called.
-		 * @param {Object} [ctx] The context object to be removed, pared with the given callback. To handle cases where
-		 * the same callback is used several times with different contexts.
-		 */
-		off( event, callback, ctx ) {
-			const callbacks = getCallbacksIfAny( this, event );
-
-			if ( !callbacks ) {
 				return;
 			}
+		}
+
+		callbacks.unshift( callback );
+	},
+
+	/**
+	 * Registers a callback function to be executed on the next time the event is fired only. This is similar to
+	 * calling {@link #on} followed by {@link #off} in the callback.
+	 *
+	 * @param {String} event The name of the event.
+	 * @param {Function} callback The function to be called on event.
+	 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to the object firing the
+	 * event.
+	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
+	 * Lower values are called first.
+	 */
+	once( event, callback, ctx, priority ) {
+		const onceCallback = function( event ) {
+			// Go off() at the first call.
+			event.off();
+
+			// Go with the original callback.
+			callback.apply( this, arguments );
+		};
+
+		// Make the a similar on() call, simply replacing the callback.
+		this.on( event, onceCallback, ctx, priority );
+	},
+
+	/**
+	 * Stops executing the callback on the given event.
+	 *
+	 * @param {String} event The name of the event.
+	 * @param {Function} callback The function to stop being called.
+	 * @param {Object} [ctx] The context object to be removed, pared with the given callback. To handle cases where
+	 * the same callback is used several times with different contexts.
+	 */
+	off( event, callback, ctx ) {
+		const callbacks = getCallbacksIfAny( this, event );
+
+		if ( !callbacks ) {
+			return;
+		}
 
-			for ( let i = 0; i < callbacks.length; i++ ) {
-				if ( callbacks[ i ].callback == callback ) {
-					if ( !ctx || ctx == callbacks[ i ].ctx ) {
-						// Remove the callback from the list (fixing the next index).
-						callbacks.splice( i, 1 );
-						i--;
-					}
+		for ( let i = 0; i < callbacks.length; i++ ) {
+			if ( callbacks[ i ].callback == callback ) {
+				if ( !ctx || ctx == callbacks[ i ].ctx ) {
+					// Remove the callback from the list (fixing the next index).
+					callbacks.splice( i, 1 );
+					i--;
 				}
 			}
-		},
-
-		/**
-		 * Registers a callback function to be executed when an event is fired in a specific (emitter) object.
-		 *
-		 * @param {Emitter} emitter The object that fires the event.
-		 * @param {String} event The name of the event.
-		 * @param {Function} callback The function to be called on event.
-		 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to `emitter`.
-		 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
-		 * Lower values are called first.
-		 */
-		listenTo( emitter, event, callback, ctx, priority ) {
-			let emitters, emitterId, emitterInfo, eventCallbacks;
-
-			// _listeningTo contains a list of emitters that this object is listening to.
-			// This list has the following format:
-			//
-			// _listeningTo: {
-			//     emitterId: {
-			//         emitter: emitter,
-			//         callbacks: {
-			//             event1: [ callback1, callback2, ... ]
-			//             ....
-			//         }
-			//     },
-			//     ...
-			// }
-
-			if ( !( emitters = this._listeningTo ) ) {
-				emitters = this._listeningTo = {};
-			}
+		}
+	},
+
+	/**
+	 * Registers a callback function to be executed when an event is fired in a specific (emitter) object.
+	 *
+	 * @param {Emitter} emitter The object that fires the event.
+	 * @param {String} event The name of the event.
+	 * @param {Function} callback The function to be called on event.
+	 * @param {Object} [ctx] The object that represents `this` in the callback. Defaults to `emitter`.
+	 * @param {Number} [priority=10] The priority of this callback in relation to other callbacks to that same event.
+	 * Lower values are called first.
+	 */
+	listenTo( emitter, event, callback, ctx, priority ) {
+		let emitters, emitterId, emitterInfo, eventCallbacks;
+
+		// _listeningTo contains a list of emitters that this object is listening to.
+		// This list has the following format:
+		//
+		// _listeningTo: {
+		//     emitterId: {
+		//         emitter: emitter,
+		//         callbacks: {
+		//             event1: [ callback1, callback2, ... ]
+		//             ....
+		//         }
+		//     },
+		//     ...
+		// }
+
+		if ( !( emitters = this._listeningTo ) ) {
+			emitters = this._listeningTo = {};
+		}
 
-			if ( !( emitterId = emitter._emitterId ) ) {
-				emitterId = emitter._emitterId = utils.uid();
-			}
+		if ( !( emitterId = emitter._emitterId ) ) {
+			emitterId = emitter._emitterId = uid();
+		}
 
-			if ( !( emitterInfo = emitters[ emitterId ] ) ) {
-				emitterInfo = emitters[ emitterId ] = {
-					emitter: emitter,
-					callbacks: {}
-				};
-			}
+		if ( !( emitterInfo = emitters[ emitterId ] ) ) {
+			emitterInfo = emitters[ emitterId ] = {
+				emitter: emitter,
+				callbacks: {}
+			};
+		}
 
-			if ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {
-				eventCallbacks = emitterInfo.callbacks[ event ] = [];
-			}
+		if ( !( eventCallbacks = emitterInfo.callbacks[ event ] ) ) {
+			eventCallbacks = emitterInfo.callbacks[ event ] = [];
+		}
 
-			eventCallbacks.push( callback );
-
-			// Finally register the callback to the event.
-			emitter.on( event, callback, ctx, priority );
-		},
-
-		/**
-		 * Stops listening for events. It can be used at different levels:
-		 *
-		 * * To stop listening to a specific callback.
-		 * * To stop listening to a specific event.
-		 * * To stop listening to all events fired by a specific object.
-		 * * To stop listening to all events fired by all object.
-		 *
-		 * @param {Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.
-		 * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it
-		 * for all events from `emitter`.
-		 * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given
-		 * `event`.
-		 */
-		stopListening( emitter, event, callback ) {
-			let emitters = this._listeningTo;
-			let emitterId = emitter && emitter._emitterId;
-			let emitterInfo = emitters && emitterId && emitters[ emitterId ];
-			let eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];
-
-			// Stop if nothing has been listened.
-			if ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {
-				return;
-			}
+		eventCallbacks.push( callback );
+
+		// Finally register the callback to the event.
+		emitter.on( event, callback, ctx, priority );
+	},
+
+	/**
+	 * Stops listening for events. It can be used at different levels:
+	 *
+	 * * To stop listening to a specific callback.
+	 * * To stop listening to a specific event.
+	 * * To stop listening to all events fired by a specific object.
+	 * * To stop listening to all events fired by all object.
+	 *
+	 * @param {Emitter} [emitter] The object to stop listening to. If omitted, stops it for all objects.
+	 * @param {String} [event] (Requires the `emitter`) The name of the event to stop listening to. If omitted, stops it
+	 * for all events from `emitter`.
+	 * @param {Function} [callback] (Requires the `event`) The function to be removed from the call list for the given
+	 * `event`.
+	 */
+	stopListening( emitter, event, callback ) {
+		let emitters = this._listeningTo;
+		let emitterId = emitter && emitter._emitterId;
+		let emitterInfo = emitters && emitterId && emitters[ emitterId ];
+		let eventCallbacks = emitterInfo && event && emitterInfo.callbacks[ event ];
+
+		// Stop if nothing has been listened.
+		if ( !emitters || ( emitter && !emitterInfo ) || ( event && !eventCallbacks ) ) {
+			return;
+		}
 
-			// All params provided. off() that single callback.
-			if ( callback ) {
+		// All params provided. off() that single callback.
+		if ( callback ) {
+			emitter.off( event, callback );
+		}
+		// Only `emitter` and `event` provided. off() all callbacks for that event.
+		else if ( eventCallbacks ) {
+			while ( ( callback = eventCallbacks.pop() ) ) {
 				emitter.off( event, callback );
 			}
-			// Only `emitter` and `event` provided. off() all callbacks for that event.
-			else if ( eventCallbacks ) {
-				while ( ( callback = eventCallbacks.pop() ) ) {
-					emitter.off( event, callback );
-				}
-				delete emitterInfo.callbacks[ event ];
-			}
-			// Only `emitter` provided. off() all events for that emitter.
-			else if ( emitterInfo ) {
-				for ( event in emitterInfo.callbacks ) {
-					this.stopListening( emitter, event );
-				}
-				delete emitters[ emitterId ];
-			}
-			// No params provided. off() all emitters.
-			else {
-				for ( emitterId in emitters ) {
-					this.stopListening( emitters[ emitterId ].emitter );
-				}
-				delete this._listeningTo;
+			delete emitterInfo.callbacks[ event ];
+		}
+		// Only `emitter` provided. off() all events for that emitter.
+		else if ( emitterInfo ) {
+			for ( event in emitterInfo.callbacks ) {
+				this.stopListening( emitter, event );
 			}
-		},
-
-		/**
-		 * Fires an event, executing all callbacks registered for it.
-		 *
-		 * The first parameter passed to callbacks is an {@link EventInfo} object, followed by the optional `args` provided in
-		 * the `fire()` method call.
-		 *
-		 * @param {String} event The name of the event.
-		 * @param {...*} [args] Additional arguments to be passed to the callbacks.
-		 */
-		fire( event, args ) {
-			const callbacks = getCallbacksIfAny( this, event );
-
-			if ( !callbacks ) {
-				return;
+			delete emitters[ emitterId ];
+		}
+		// No params provided. off() all emitters.
+		else {
+			for ( emitterId in emitters ) {
+				this.stopListening( emitters[ emitterId ].emitter );
 			}
+			delete this._listeningTo;
+		}
+	},
+
+	/**
+	 * Fires an event, executing all callbacks registered for it.
+	 *
+	 * The first parameter passed to callbacks is an {@link EventInfo} object, followed by the optional `args` provided in
+	 * the `fire()` method call.
+	 *
+	 * @param {String} event The name of the event.
+	 * @param {...*} [args] Additional arguments to be passed to the callbacks.
+	 */
+	fire( event, args ) {
+		const callbacks = getCallbacksIfAny( this, event );
+
+		if ( !callbacks ) {
+			return;
+		}
 
-			let eventInfo = new EventInfo( this, event );
+		let eventInfo = new EventInfo( this, event );
 
-			// Take the list of arguments to pass to the callbacks.
-			args = Array.prototype.slice.call( arguments, 1 );
-			args.unshift( eventInfo );
+		// Take the list of arguments to pass to the callbacks.
+		args = Array.prototype.slice.call( arguments, 1 );
+		args.unshift( eventInfo );
 
-			for ( let i = 0; i < callbacks.length; i++ ) {
-				callbacks[ i ].callback.apply( callbacks[ i ].ctx, args );
+		for ( let i = 0; i < callbacks.length; i++ ) {
+			callbacks[ i ].callback.apply( callbacks[ i ].ctx, args );
 
-				// Remove the callback from future requests if off() has been called.
-				if ( eventInfo.off.called ) {
-					// Remove the called mark for the next calls.
-					delete eventInfo.off.called;
+			// Remove the callback from future requests if off() has been called.
+			if ( eventInfo.off.called ) {
+				// Remove the called mark for the next calls.
+				delete eventInfo.off.called;
 
-					// Remove the callback from the list (fixing the next index).
-					callbacks.splice( i, 1 );
-					i--;
-				}
+				// Remove the callback from the list (fixing the next index).
+				callbacks.splice( i, 1 );
+				i--;
+			}
 
-				// Do not execute next callbacks if stop() was called.
-				if ( eventInfo.stop.called ) {
-					break;
-				}
+			// Do not execute next callbacks if stop() was called.
+			if ( eventInfo.stop.called ) {
+				break;
 			}
 		}
-	};
-
-	return EmitterMixin;
+	}
+};
 
-	// Gets the internal events hash of a give object.
-	function getEvents( source ) {
-		if ( !source._events ) {
-			Object.defineProperty( source, '_events', {
-				value: {}
-			} );
-		}
+export default EmitterMixin;
 
-		return source._events;
+// Gets the internal events hash of a give object.
+function getEvents( source ) {
+	if ( !source._events ) {
+		Object.defineProperty( source, '_events', {
+			value: {}
+		} );
 	}
 
-	// Gets the list of callbacks for a given event.
-	function getCallbacks( source, eventName ) {
-		const events = getEvents( source );
+	return source._events;
+}
 
-		if ( !events[ eventName ] ) {
-			events[ eventName ] = [];
-		}
+// Gets the list of callbacks for a given event.
+function getCallbacks( source, eventName ) {
+	const events = getEvents( source );
 
-		return events[ eventName ];
+	if ( !events[ eventName ] ) {
+		events[ eventName ] = [];
 	}
 
-	// Get the list of callbacks for a given event only if there is any available.
-	function getCallbacksIfAny( source, event ) {
-		let callbacks;
+	return events[ eventName ];
+}
 
-		if ( !source._events || !( callbacks = source._events[ event ] ) || !callbacks.length ) {
-			return null;
-		}
+// Get the list of callbacks for a given event only if there is any available.
+function getCallbacksIfAny( source, event ) {
+	let callbacks;
 
-		return callbacks;
+	if ( !source._events || !( callbacks = source._events[ event ] ) || !callbacks.length ) {
+		return null;
 	}
-} );
+
+	return callbacks;
+}

+ 30 - 32
packages/ckeditor5-ui/src/eventinfo.js

@@ -12,36 +12,34 @@
  * @class EventInfo
  */
 
-CKEDITOR.define( [ 'utils' ], ( utils ) => {
-	class EventInfo {
-		constructor( source, name ) {
-			/**
-			 * The object that fired the event.
-			 */
-			this.source = source;
-
-			/**
-			 * The event name.
-			 */
-			this.name = name;
-
-			// The following methods are defined in the constructor because they must be re-created per instance.
-
-			/**
-			 * Stops the event emitter to call further callbacks for this event interaction.
-			 *
-			 * @method
-			 */
-			this.stop = utils.spy();
-
-			/**
-			 * Removes the current callback from future interactions of this event.
-			 *
-			 * @method
-			 */
-			this.off = utils.spy();
-		}
+import { spy } from './utils.js';
+
+export default class EventInfo {
+	constructor( source, name ) {
+		/**
+		 * The object that fired the event.
+		 */
+		this.source = source;
+
+		/**
+		 * The event name.
+		 */
+		this.name = name;
+
+		// The following methods are defined in the constructor because they must be re-created per instance.
+
+		/**
+		 * Stops the event emitter to call further callbacks for this event interaction.
+		 *
+		 * @method
+		 */
+		this.stop = spy();
+
+		/**
+		 * Removes the current callback from future interactions of this event.
+		 *
+		 * @method
+		 */
+		this.off = spy();
 	}
-
-	return EventInfo;
-} );
+}

+ 5 - 0
packages/ckeditor5-ui/src/lib/lodash/array.js

@@ -0,0 +1,5 @@
+import last from './array/last';
+
+export default {
+  'last': last
+};

+ 28 - 0
packages/ckeditor5-ui/src/lib/lodash/array/last.js

@@ -0,0 +1,28 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+
+/**
+ * Gets the last element of `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to query.
+ * @returns {*} Returns the last element of `array`.
+ * @example
+ *
+ * _.last([1, 2, 3]);
+ * // => 3
+ */
+function last(array) {
+  var length = array ? array.length : 0;
+  return length ? array[length - 1] : undefined;
+}
+
+export default last;

+ 5 - 0
packages/ckeditor5-ui/src/lib/lodash/function.js

@@ -0,0 +1,5 @@
+import restParam from './function/restParam';
+
+export default {
+  'restParam': restParam
+};

+ 58 - 0
packages/ckeditor5-ui/src/lib/lodash/function/restParam.js

@@ -0,0 +1,58 @@
+/** Used as the `TypeError` message for "Functions" methods. */
+var FUNC_ERROR_TEXT = 'Expected a function';
+
+/* Native method references for those with the same name as other `lodash` methods. */
+var nativeMax = Math.max;
+
+/**
+ * Creates a function that invokes `func` with the `this` binding of the
+ * created function and arguments from `start` and beyond provided as an array.
+ *
+ * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters).
+ *
+ * @static
+ * @memberOf _
+ * @category Function
+ * @param {Function} func The function to apply a rest parameter to.
+ * @param {number} [start=func.length-1] The start position of the rest parameter.
+ * @returns {Function} Returns the new function.
+ * @example
+ *
+ * var say = _.restParam(function(what, names) {
+ *   return what + ' ' + _.initial(names).join(', ') +
+ *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
+ * });
+ *
+ * say('hello', 'fred', 'barney', 'pebbles');
+ * // => 'hello fred, barney, & pebbles'
+ */
+function restParam(func, start) {
+  if (typeof func != 'function') {
+    throw new TypeError(FUNC_ERROR_TEXT);
+  }
+  start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
+  return function() {
+    var args = arguments,
+        index = -1,
+        length = nativeMax(args.length - start, 0),
+        rest = Array(length);
+
+    while (++index < length) {
+      rest[index] = args[start + index];
+    }
+    switch (start) {
+      case 0: return func.call(this, rest);
+      case 1: return func.call(this, args[0], rest);
+      case 2: return func.call(this, args[0], args[1], rest);
+    }
+    var otherArgs = Array(start + 1);
+    index = -1;
+    while (++index < start) {
+      otherArgs[index] = args[index];
+    }
+    otherArgs[start] = rest;
+    return func.apply(this, otherArgs);
+  };
+}
+
+export default restParam;

+ 20 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/arrayCopy.js

@@ -0,0 +1,20 @@
+/**
+ * Copies the values of `source` to `array`.
+ *
+ * @private
+ * @param {Array} source The array to copy values from.
+ * @param {Array} [array=[]] The array to copy values to.
+ * @returns {Array} Returns `array`.
+ */
+function arrayCopy(source, array) {
+  var index = -1,
+      length = source.length;
+
+  array || (array = Array(length));
+  while (++index < length) {
+    array[index] = source[index];
+  }
+  return array;
+}
+
+export default arrayCopy;

+ 22 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/arrayEach.js

@@ -0,0 +1,22 @@
+/**
+ * A specialized version of `_.forEach` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Array} Returns `array`.
+ */
+function arrayEach(array, iteratee) {
+  var index = -1,
+      length = array.length;
+
+  while (++index < length) {
+    if (iteratee(array[index], index, array) === false) {
+      break;
+    }
+  }
+  return array;
+}
+
+export default arrayEach;

+ 23 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/arraySome.js

@@ -0,0 +1,23 @@
+/**
+ * A specialized version of `_.some` for arrays without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} predicate The function invoked per iteration.
+ * @returns {boolean} Returns `true` if any element passes the predicate check,
+ *  else `false`.
+ */
+function arraySome(array, predicate) {
+  var index = -1,
+      length = array.length;
+
+  while (++index < length) {
+    if (predicate(array[index], index, array)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+export default arraySome;

+ 32 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/assignWith.js

@@ -0,0 +1,32 @@
+import keys from '../object/keys';
+
+/**
+ * A specialized version of `_.assign` for customizing assigned values without
+ * support for argument juggling, multiple sources, and `this` binding `customizer`
+ * functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @param {Function} customizer The function to customize assigned values.
+ * @returns {Object} Returns `object`.
+ */
+function assignWith(object, source, customizer) {
+  var index = -1,
+      props = keys(source),
+      length = props.length;
+
+  while (++index < length) {
+    var key = props[index],
+        value = object[key],
+        result = customizer(value, source[key], key, object, source);
+
+    if ((result === result ? (result !== value) : (value === value)) ||
+        (value === undefined && !(key in object))) {
+      object[key] = result;
+    }
+  }
+  return object;
+}
+
+export default assignWith;

+ 19 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseAssign.js

@@ -0,0 +1,19 @@
+import baseCopy from './baseCopy';
+import keys from '../object/keys';
+
+/**
+ * The base implementation of `_.assign` without support for argument juggling,
+ * multiple sources, and `customizer` functions.
+ *
+ * @private
+ * @param {Object} object The destination object.
+ * @param {Object} source The source object.
+ * @returns {Object} Returns `object`.
+ */
+function baseAssign(object, source) {
+  return source == null
+    ? object
+    : baseCopy(source, keys(source), object);
+}
+
+export default baseAssign;

+ 128 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseClone.js

@@ -0,0 +1,128 @@
+import arrayCopy from './arrayCopy';
+import arrayEach from './arrayEach';
+import baseAssign from './baseAssign';
+import baseForOwn from './baseForOwn';
+import initCloneArray from './initCloneArray';
+import initCloneByTag from './initCloneByTag';
+import initCloneObject from './initCloneObject';
+import isArray from '../lang/isArray';
+import isObject from '../lang/isObject';
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]',
+    arrayTag = '[object Array]',
+    boolTag = '[object Boolean]',
+    dateTag = '[object Date]',
+    errorTag = '[object Error]',
+    funcTag = '[object Function]',
+    mapTag = '[object Map]',
+    numberTag = '[object Number]',
+    objectTag = '[object Object]',
+    regexpTag = '[object RegExp]',
+    setTag = '[object Set]',
+    stringTag = '[object String]',
+    weakMapTag = '[object WeakMap]';
+
+var arrayBufferTag = '[object ArrayBuffer]',
+    float32Tag = '[object Float32Array]',
+    float64Tag = '[object Float64Array]',
+    int8Tag = '[object Int8Array]',
+    int16Tag = '[object Int16Array]',
+    int32Tag = '[object Int32Array]',
+    uint8Tag = '[object Uint8Array]',
+    uint8ClampedTag = '[object Uint8ClampedArray]',
+    uint16Tag = '[object Uint16Array]',
+    uint32Tag = '[object Uint32Array]';
+
+/** Used to identify `toStringTag` values supported by `_.clone`. */
+var cloneableTags = {};
+cloneableTags[argsTag] = cloneableTags[arrayTag] =
+cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
+cloneableTags[dateTag] = cloneableTags[float32Tag] =
+cloneableTags[float64Tag] = cloneableTags[int8Tag] =
+cloneableTags[int16Tag] = cloneableTags[int32Tag] =
+cloneableTags[numberTag] = cloneableTags[objectTag] =
+cloneableTags[regexpTag] = cloneableTags[stringTag] =
+cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
+cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
+cloneableTags[errorTag] = cloneableTags[funcTag] =
+cloneableTags[mapTag] = cloneableTags[setTag] =
+cloneableTags[weakMapTag] = false;
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/**
+ * The base implementation of `_.clone` without support for argument juggling
+ * and `this` binding `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {string} [key] The key of `value`.
+ * @param {Object} [object] The object `value` belongs to.
+ * @param {Array} [stackA=[]] Tracks traversed source objects.
+ * @param {Array} [stackB=[]] Associates clones with source counterparts.
+ * @returns {*} Returns the cloned value.
+ */
+function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
+  var result;
+  if (customizer) {
+    result = object ? customizer(value, key, object) : customizer(value);
+  }
+  if (result !== undefined) {
+    return result;
+  }
+  if (!isObject(value)) {
+    return value;
+  }
+  var isArr = isArray(value);
+  if (isArr) {
+    result = initCloneArray(value);
+    if (!isDeep) {
+      return arrayCopy(value, result);
+    }
+  } else {
+    var tag = objToString.call(value),
+        isFunc = tag == funcTag;
+
+    if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
+      result = initCloneObject(isFunc ? {} : value);
+      if (!isDeep) {
+        return baseAssign(result, value);
+      }
+    } else {
+      return cloneableTags[tag]
+        ? initCloneByTag(value, tag, isDeep)
+        : (object ? value : {});
+    }
+  }
+  // Check for circular references and return its corresponding clone.
+  stackA || (stackA = []);
+  stackB || (stackB = []);
+
+  var length = stackA.length;
+  while (length--) {
+    if (stackA[length] == value) {
+      return stackB[length];
+    }
+  }
+  // Add the source value to the stack of traversed objects and associate it with its clone.
+  stackA.push(value);
+  stackB.push(result);
+
+  // Recursively populate clone (susceptible to call stack limits).
+  (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
+    result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
+  });
+  return result;
+}
+
+export default baseClone;

+ 23 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseCopy.js

@@ -0,0 +1,23 @@
+/**
+ * Copies properties of `source` to `object`.
+ *
+ * @private
+ * @param {Object} source The object to copy properties from.
+ * @param {Array} props The property names to copy.
+ * @param {Object} [object={}] The object to copy properties to.
+ * @returns {Object} Returns `object`.
+ */
+function baseCopy(source, props, object) {
+  object || (object = {});
+
+  var index = -1,
+      length = props.length;
+
+  while (++index < length) {
+    var key = props[index];
+    object[key] = source[key];
+  }
+  return object;
+}
+
+export default baseCopy;

+ 17 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseFor.js

@@ -0,0 +1,17 @@
+import createBaseFor from './createBaseFor';
+
+/**
+ * The base implementation of `baseForIn` and `baseForOwn` which iterates
+ * over `object` properties returned by `keysFunc` invoking `iteratee` for
+ * each property. Iteratee functions may exit iteration early by explicitly
+ * returning `false`.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @param {Function} keysFunc The function to get the keys of `object`.
+ * @returns {Object} Returns `object`.
+ */
+var baseFor = createBaseFor();
+
+export default baseFor;

+ 17 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseForIn.js

@@ -0,0 +1,17 @@
+import baseFor from './baseFor';
+import keysIn from '../object/keysIn';
+
+/**
+ * The base implementation of `_.forIn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+function baseForIn(object, iteratee) {
+  return baseFor(object, iteratee, keysIn);
+}
+
+export default baseForIn;

+ 17 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseForOwn.js

@@ -0,0 +1,17 @@
+import baseFor from './baseFor';
+import keys from '../object/keys';
+
+/**
+ * The base implementation of `_.forOwn` without support for callback
+ * shorthands and `this` binding.
+ *
+ * @private
+ * @param {Object} object The object to iterate over.
+ * @param {Function} iteratee The function invoked per iteration.
+ * @returns {Object} Returns `object`.
+ */
+function baseForOwn(object, iteratee) {
+  return baseFor(object, iteratee, keys);
+}
+
+export default baseForOwn;

+ 28 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseIsEqual.js

@@ -0,0 +1,28 @@
+import baseIsEqualDeep from './baseIsEqualDeep';
+import isObject from '../lang/isObject';
+import isObjectLike from './isObjectLike';
+
+/**
+ * The base implementation of `_.isEqual` without support for `this` binding
+ * `customizer` functions.
+ *
+ * @private
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ */
+function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
+  if (value === other) {
+    return true;
+  }
+  if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
+    return value !== value && other !== other;
+  }
+  return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
+}
+
+export default baseIsEqual;

+ 102 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseIsEqualDeep.js

@@ -0,0 +1,102 @@
+import equalArrays from './equalArrays';
+import equalByTag from './equalByTag';
+import equalObjects from './equalObjects';
+import isArray from '../lang/isArray';
+import isTypedArray from '../lang/isTypedArray';
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]',
+    arrayTag = '[object Array]',
+    objectTag = '[object Object]';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/**
+ * A specialized version of `baseIsEqual` for arrays and objects which performs
+ * deep comparisons and tracks traversed objects enabling objects with circular
+ * references to be compared.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing objects.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA=[]] Tracks traversed `value` objects.
+ * @param {Array} [stackB=[]] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
+  var objIsArr = isArray(object),
+      othIsArr = isArray(other),
+      objTag = arrayTag,
+      othTag = arrayTag;
+
+  if (!objIsArr) {
+    objTag = objToString.call(object);
+    if (objTag == argsTag) {
+      objTag = objectTag;
+    } else if (objTag != objectTag) {
+      objIsArr = isTypedArray(object);
+    }
+  }
+  if (!othIsArr) {
+    othTag = objToString.call(other);
+    if (othTag == argsTag) {
+      othTag = objectTag;
+    } else if (othTag != objectTag) {
+      othIsArr = isTypedArray(other);
+    }
+  }
+  var objIsObj = objTag == objectTag,
+      othIsObj = othTag == objectTag,
+      isSameTag = objTag == othTag;
+
+  if (isSameTag && !(objIsArr || objIsObj)) {
+    return equalByTag(object, other, objTag);
+  }
+  if (!isLoose) {
+    var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
+        othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
+
+    if (objIsWrapped || othIsWrapped) {
+      return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
+    }
+  }
+  if (!isSameTag) {
+    return false;
+  }
+  // Assume cyclic values are equal.
+  // For more information on detecting circular references see https://es5.github.io/#JO.
+  stackA || (stackA = []);
+  stackB || (stackB = []);
+
+  var length = stackA.length;
+  while (length--) {
+    if (stackA[length] == object) {
+      return stackB[length] == other;
+    }
+  }
+  // Add `object` and `other` to the stack of traversed objects.
+  stackA.push(object);
+  stackB.push(other);
+
+  var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
+
+  stackA.pop();
+  stackB.pop();
+
+  return result;
+}
+
+export default baseIsEqualDeep;

+ 14 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/baseProperty.js

@@ -0,0 +1,14 @@
+/**
+ * The base implementation of `_.property` without support for deep paths.
+ *
+ * @private
+ * @param {string} key The key of the property to get.
+ * @returns {Function} Returns the new function.
+ */
+function baseProperty(key) {
+  return function(object) {
+    return object == null ? undefined : object[key];
+  };
+}
+
+export default baseProperty;

+ 39 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/bindCallback.js

@@ -0,0 +1,39 @@
+import identity from '../utility/identity';
+
+/**
+ * A specialized version of `baseCallback` which only supports `this` binding
+ * and specifying the number of arguments to provide to `func`.
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {*} thisArg The `this` binding of `func`.
+ * @param {number} [argCount] The number of arguments to provide to `func`.
+ * @returns {Function} Returns the callback.
+ */
+function bindCallback(func, thisArg, argCount) {
+  if (typeof func != 'function') {
+    return identity;
+  }
+  if (thisArg === undefined) {
+    return func;
+  }
+  switch (argCount) {
+    case 1: return function(value) {
+      return func.call(thisArg, value);
+    };
+    case 3: return function(value, index, collection) {
+      return func.call(thisArg, value, index, collection);
+    };
+    case 4: return function(accumulator, value, index, collection) {
+      return func.call(thisArg, accumulator, value, index, collection);
+    };
+    case 5: return function(value, other, key, object, source) {
+      return func.call(thisArg, value, other, key, object, source);
+    };
+  }
+  return function() {
+    return func.apply(thisArg, arguments);
+  };
+}
+
+export default bindCallback;

+ 22 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/bufferClone.js

@@ -0,0 +1,22 @@
+import root from './root';
+
+/** Native method references. */
+var ArrayBuffer = root.ArrayBuffer,
+    Uint8Array = root.Uint8Array;
+
+/**
+ * Creates a clone of the given array buffer.
+ *
+ * @private
+ * @param {ArrayBuffer} buffer The array buffer to clone.
+ * @returns {ArrayBuffer} Returns the cloned array buffer.
+ */
+function bufferClone(buffer) {
+  var result = new ArrayBuffer(buffer.byteLength),
+      view = new Uint8Array(result);
+
+  view.set(new Uint8Array(buffer));
+  return result;
+}
+
+export default bufferClone;

+ 41 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/createAssigner.js

@@ -0,0 +1,41 @@
+import bindCallback from './bindCallback';
+import isIterateeCall from './isIterateeCall';
+import restParam from '../function/restParam';
+
+/**
+ * Creates a `_.assign`, `_.defaults`, or `_.merge` function.
+ *
+ * @private
+ * @param {Function} assigner The function to assign values.
+ * @returns {Function} Returns the new assigner function.
+ */
+function createAssigner(assigner) {
+  return restParam(function(object, sources) {
+    var index = -1,
+        length = object == null ? 0 : sources.length,
+        customizer = length > 2 ? sources[length - 2] : undefined,
+        guard = length > 2 ? sources[2] : undefined,
+        thisArg = length > 1 ? sources[length - 1] : undefined;
+
+    if (typeof customizer == 'function') {
+      customizer = bindCallback(customizer, thisArg, 5);
+      length -= 2;
+    } else {
+      customizer = typeof thisArg == 'function' ? thisArg : undefined;
+      length -= (customizer ? 1 : 0);
+    }
+    if (guard && isIterateeCall(sources[0], sources[1], guard)) {
+      customizer = length < 3 ? undefined : customizer;
+      length = 1;
+    }
+    while (++index < length) {
+      var source = sources[index];
+      if (source) {
+        assigner(object, source, customizer);
+      }
+    }
+    return object;
+  });
+}
+
+export default createAssigner;

+ 27 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/createBaseFor.js

@@ -0,0 +1,27 @@
+import toObject from './toObject';
+
+/**
+ * Creates a base function for `_.forIn` or `_.forInRight`.
+ *
+ * @private
+ * @param {boolean} [fromRight] Specify iterating from right to left.
+ * @returns {Function} Returns the new base function.
+ */
+function createBaseFor(fromRight) {
+  return function(object, iteratee, keysFunc) {
+    var iterable = toObject(object),
+        props = keysFunc(object),
+        length = props.length,
+        index = fromRight ? length : -1;
+
+    while ((fromRight ? index-- : ++index < length)) {
+      var key = props[index];
+      if (iteratee(iterable[key], key, iterable) === false) {
+        break;
+      }
+    }
+    return object;
+  };
+}
+
+export default createBaseFor;

+ 51 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/equalArrays.js

@@ -0,0 +1,51 @@
+import arraySome from './arraySome';
+
+/**
+ * A specialized version of `baseIsEqualDeep` for arrays with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Array} array The array to compare.
+ * @param {Array} other The other array to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing arrays.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
+ */
+function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
+  var index = -1,
+      arrLength = array.length,
+      othLength = other.length;
+
+  if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
+    return false;
+  }
+  // Ignore non-index properties.
+  while (++index < arrLength) {
+    var arrValue = array[index],
+        othValue = other[index],
+        result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined;
+
+    if (result !== undefined) {
+      if (result) {
+        continue;
+      }
+      return false;
+    }
+    // Recursively compare arrays (susceptible to call stack limits).
+    if (isLoose) {
+      if (!arraySome(other, function(othValue) {
+            return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
+          })) {
+        return false;
+      }
+    } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+export default equalArrays;

+ 48 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/equalByTag.js

@@ -0,0 +1,48 @@
+/** `Object#toString` result references. */
+var boolTag = '[object Boolean]',
+    dateTag = '[object Date]',
+    errorTag = '[object Error]',
+    numberTag = '[object Number]',
+    regexpTag = '[object RegExp]',
+    stringTag = '[object String]';
+
+/**
+ * A specialized version of `baseIsEqualDeep` for comparing objects of
+ * the same `toStringTag`.
+ *
+ * **Note:** This function only supports comparing values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {string} tag The `toStringTag` of the objects to compare.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+function equalByTag(object, other, tag) {
+  switch (tag) {
+    case boolTag:
+    case dateTag:
+      // Coerce dates and booleans to numbers, dates to milliseconds and booleans
+      // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
+      return +object == +other;
+
+    case errorTag:
+      return object.name == other.name && object.message == other.message;
+
+    case numberTag:
+      // Treat `NaN` vs. `NaN` as equal.
+      return (object != +object)
+        ? other != +other
+        : object == +other;
+
+    case regexpTag:
+    case stringTag:
+      // Coerce regexes to strings and treat strings primitives and string
+      // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
+      return object == (other + '');
+  }
+  return false;
+}
+
+export default equalByTag;

+ 67 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/equalObjects.js

@@ -0,0 +1,67 @@
+import keys from '../object/keys';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * A specialized version of `baseIsEqualDeep` for objects with support for
+ * partial deep comparisons.
+ *
+ * @private
+ * @param {Object} object The object to compare.
+ * @param {Object} other The other object to compare.
+ * @param {Function} equalFunc The function to determine equivalents of values.
+ * @param {Function} [customizer] The function to customize comparing values.
+ * @param {boolean} [isLoose] Specify performing partial comparisons.
+ * @param {Array} [stackA] Tracks traversed `value` objects.
+ * @param {Array} [stackB] Tracks traversed `other` objects.
+ * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
+ */
+function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
+  var objProps = keys(object),
+      objLength = objProps.length,
+      othProps = keys(other),
+      othLength = othProps.length;
+
+  if (objLength != othLength && !isLoose) {
+    return false;
+  }
+  var index = objLength;
+  while (index--) {
+    var key = objProps[index];
+    if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
+      return false;
+    }
+  }
+  var skipCtor = isLoose;
+  while (++index < objLength) {
+    key = objProps[index];
+    var objValue = object[key],
+        othValue = other[key],
+        result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined;
+
+    // Recursively compare objects (susceptible to call stack limits).
+    if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) {
+      return false;
+    }
+    skipCtor || (skipCtor = key == 'constructor');
+  }
+  if (!skipCtor) {
+    var objCtor = object.constructor,
+        othCtor = other.constructor;
+
+    // Non `Object` object instances with different constructors are not equal.
+    if (objCtor != othCtor &&
+        ('constructor' in object && 'constructor' in other) &&
+        !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
+          typeof othCtor == 'function' && othCtor instanceof othCtor)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+export default equalObjects;

+ 15 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/getLength.js

@@ -0,0 +1,15 @@
+import baseProperty from './baseProperty';
+
+/**
+ * Gets the "length" property value of `object`.
+ *
+ * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
+ * that affects Safari on at least iOS 8.1-8.3 ARM64.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {*} Returns the "length" value.
+ */
+var getLength = baseProperty('length');
+
+export default getLength;

+ 16 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/getNative.js

@@ -0,0 +1,16 @@
+import isNative from '../lang/isNative';
+
+/**
+ * Gets the native function at `key` of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @param {string} key The key of the method to get.
+ * @returns {*} Returns the function if it's native, else `undefined`.
+ */
+function getNative(object, key) {
+  var value = object == null ? undefined : object[key];
+  return isNative(value) ? value : undefined;
+}
+
+export default getNative;

+ 26 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/initCloneArray.js

@@ -0,0 +1,26 @@
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Initializes an array clone.
+ *
+ * @private
+ * @param {Array} array The array to clone.
+ * @returns {Array} Returns the initialized clone.
+ */
+function initCloneArray(array) {
+  var length = array.length,
+      result = new array.constructor(length);
+
+  // Add array properties assigned by `RegExp#exec`.
+  if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
+    result.index = array.index;
+    result.input = array.input;
+  }
+  return result;
+}
+
+export default initCloneArray;

+ 63 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/initCloneByTag.js

@@ -0,0 +1,63 @@
+import bufferClone from './bufferClone';
+
+/** `Object#toString` result references. */
+var boolTag = '[object Boolean]',
+    dateTag = '[object Date]',
+    numberTag = '[object Number]',
+    regexpTag = '[object RegExp]',
+    stringTag = '[object String]';
+
+var arrayBufferTag = '[object ArrayBuffer]',
+    float32Tag = '[object Float32Array]',
+    float64Tag = '[object Float64Array]',
+    int8Tag = '[object Int8Array]',
+    int16Tag = '[object Int16Array]',
+    int32Tag = '[object Int32Array]',
+    uint8Tag = '[object Uint8Array]',
+    uint8ClampedTag = '[object Uint8ClampedArray]',
+    uint16Tag = '[object Uint16Array]',
+    uint32Tag = '[object Uint32Array]';
+
+/** Used to match `RegExp` flags from their coerced string values. */
+var reFlags = /\w*$/;
+
+/**
+ * Initializes an object clone based on its `toStringTag`.
+ *
+ * **Note:** This function only supports cloning values with tags of
+ * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @param {string} tag The `toStringTag` of the object to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+function initCloneByTag(object, tag, isDeep) {
+  var Ctor = object.constructor;
+  switch (tag) {
+    case arrayBufferTag:
+      return bufferClone(object);
+
+    case boolTag:
+    case dateTag:
+      return new Ctor(+object);
+
+    case float32Tag: case float64Tag:
+    case int8Tag: case int16Tag: case int32Tag:
+    case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
+      var buffer = object.buffer;
+      return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
+
+    case numberTag:
+    case stringTag:
+      return new Ctor(object);
+
+    case regexpTag:
+      var result = new Ctor(object.source, reFlags.exec(object));
+      result.lastIndex = object.lastIndex;
+  }
+  return result;
+}
+
+export default initCloneByTag;

+ 16 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/initCloneObject.js

@@ -0,0 +1,16 @@
+/**
+ * Initializes an object clone.
+ *
+ * @private
+ * @param {Object} object The object to clone.
+ * @returns {Object} Returns the initialized clone.
+ */
+function initCloneObject(object) {
+  var Ctor = object.constructor;
+  if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
+    Ctor = Object;
+  }
+  return new Ctor;
+}
+
+export default initCloneObject;

+ 15 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/isArrayLike.js

@@ -0,0 +1,15 @@
+import getLength from './getLength';
+import isLength from './isLength';
+
+/**
+ * Checks if `value` is array-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ */
+function isArrayLike(value) {
+  return value != null && isLength(getLength(value));
+}
+
+export default isArrayLike;

+ 24 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/isIndex.js

@@ -0,0 +1,24 @@
+/** Used to detect unsigned integer values. */
+var reIsUint = /^\d+$/;
+
+/**
+ * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
+ * of an array-like value.
+ */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/**
+ * Checks if `value` is a valid array-like index.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
+ * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
+ */
+function isIndex(value, length) {
+  value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
+  length = length == null ? MAX_SAFE_INTEGER : length;
+  return value > -1 && value % 1 == 0 && value < length;
+}
+
+export default isIndex;

+ 28 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/isIterateeCall.js

@@ -0,0 +1,28 @@
+import isArrayLike from './isArrayLike';
+import isIndex from './isIndex';
+import isObject from '../lang/isObject';
+
+/**
+ * Checks if the provided arguments are from an iteratee call.
+ *
+ * @private
+ * @param {*} value The potential iteratee value argument.
+ * @param {*} index The potential iteratee index or key argument.
+ * @param {*} object The potential iteratee object argument.
+ * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
+ */
+function isIterateeCall(value, index, object) {
+  if (!isObject(object)) {
+    return false;
+  }
+  var type = typeof index;
+  if (type == 'number'
+      ? (isArrayLike(object) && isIndex(index, object.length))
+      : (type == 'string' && index in object)) {
+    var other = object[index];
+    return value === value ? (value === other) : (other !== other);
+  }
+  return false;
+}
+
+export default isIterateeCall;

+ 20 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/isLength.js

@@ -0,0 +1,20 @@
+/**
+ * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
+ * of an array-like value.
+ */
+var MAX_SAFE_INTEGER = 9007199254740991;
+
+/**
+ * Checks if `value` is a valid array-like length.
+ *
+ * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
+ */
+function isLength(value) {
+  return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
+}
+
+export default isLength;

+ 12 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/isObjectLike.js

@@ -0,0 +1,12 @@
+/**
+ * Checks if `value` is object-like.
+ *
+ * @private
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
+ */
+function isObjectLike(value) {
+  return !!value && typeof value == 'object';
+}
+
+export default isObjectLike;

+ 30 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/root.js

@@ -0,0 +1,30 @@
+/** Used to determine if values are of the language type `Object`. */
+var objectTypes = {
+  'function': true,
+  'object': true
+};
+
+/** Detect free variable `exports`. */
+var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
+
+/** Detect free variable `module`. */
+var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
+
+/** Detect free variable `global` from Node.js. */
+var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;
+
+/** Detect free variable `self`. */
+var freeSelf = objectTypes[typeof self] && self && self.Object && self;
+
+/** Detect free variable `window`. */
+var freeWindow = objectTypes[typeof window] && window && window.Object && window;
+
+/**
+ * Used as a reference to the global object.
+ *
+ * The `this` value is used if it's the global object to avoid Greasemonkey's
+ * restricted `window` object, otherwise the `window` object is used.
+ */
+var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
+
+export default root;

+ 41 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/shimKeys.js

@@ -0,0 +1,41 @@
+import isArguments from '../lang/isArguments';
+import isArray from '../lang/isArray';
+import isIndex from './isIndex';
+import isLength from './isLength';
+import keysIn from '../object/keysIn';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * A fallback implementation of `Object.keys` which creates an array of the
+ * own enumerable property names of `object`.
+ *
+ * @private
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ */
+function shimKeys(object) {
+  var props = keysIn(object),
+      propsLength = props.length,
+      length = propsLength && object.length;
+
+  var allowIndexes = !!length && isLength(length) &&
+    (isArray(object) || isArguments(object));
+
+  var index = -1,
+      result = [];
+
+  while (++index < propsLength) {
+    var key = props[index];
+    if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
+      result.push(key);
+    }
+  }
+  return result;
+}
+
+export default shimKeys;

+ 14 - 0
packages/ckeditor5-ui/src/lib/lodash/internal/toObject.js

@@ -0,0 +1,14 @@
+import isObject from '../lang/isObject';
+
+/**
+ * Converts `value` to an object if it's not one.
+ *
+ * @private
+ * @param {*} value The value to process.
+ * @returns {Object} Returns the object.
+ */
+function toObject(value) {
+  return isObject(value) ? value : Object(value);
+}
+
+export default toObject;

+ 23 - 0
packages/ckeditor5-ui/src/lib/lodash/lang.js

@@ -0,0 +1,23 @@
+import clone from './lang/clone';
+import eq from './lang/eq';
+import isArguments from './lang/isArguments';
+import isArray from './lang/isArray';
+import isEqual from './lang/isEqual';
+import isFunction from './lang/isFunction';
+import isNative from './lang/isNative';
+import isObject from './lang/isObject';
+import isPlainObject from './lang/isPlainObject';
+import isTypedArray from './lang/isTypedArray';
+
+export default {
+  'clone': clone,
+  'eq': eq,
+  'isArguments': isArguments,
+  'isArray': isArray,
+  'isEqual': isEqual,
+  'isFunction': isFunction,
+  'isNative': isNative,
+  'isObject': isObject,
+  'isPlainObject': isPlainObject,
+  'isTypedArray': isTypedArray
+};

+ 78 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/clone.js

@@ -0,0 +1,78 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+import baseClone from '../internal/baseClone';
+import bindCallback from '../internal/bindCallback';
+import isIterateeCall from '../internal/isIterateeCall';
+
+/**
+ * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
+ * otherwise they are assigned by reference. If `customizer` is provided it's
+ * invoked to produce the cloned values. If `customizer` returns `undefined`
+ * cloning is handled by the method instead. The `customizer` is bound to
+ * `thisArg` and invoked with up to three argument; (value [, index|key, object]).
+ *
+ * **Note:** This method is loosely based on the
+ * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
+ * The enumerable properties of `arguments` objects and objects created by
+ * constructors other than `Object` are cloned to plain `Object` objects. An
+ * empty object is returned for uncloneable values such as functions, DOM nodes,
+ * Maps, Sets, and WeakMaps.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to clone.
+ * @param {boolean} [isDeep] Specify a deep clone.
+ * @param {Function} [customizer] The function to customize cloning values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {*} Returns the cloned value.
+ * @example
+ *
+ * var users = [
+ *   { 'user': 'barney' },
+ *   { 'user': 'fred' }
+ * ];
+ *
+ * var shallow = _.clone(users);
+ * shallow[0] === users[0];
+ * // => true
+ *
+ * var deep = _.clone(users, true);
+ * deep[0] === users[0];
+ * // => false
+ *
+ * // using a customizer callback
+ * var el = _.clone(document.body, function(value) {
+ *   if (_.isElement(value)) {
+ *     return value.cloneNode(false);
+ *   }
+ * });
+ *
+ * el === document.body
+ * // => false
+ * el.nodeName
+ * // => BODY
+ * el.childNodes.length;
+ * // => 0
+ */
+function clone(value, isDeep, customizer, thisArg) {
+  if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
+    isDeep = false;
+  }
+  else if (typeof isDeep == 'function') {
+    thisArg = customizer;
+    customizer = isDeep;
+    isDeep = false;
+  }
+  return typeof customizer == 'function'
+    ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 3))
+    : baseClone(value, isDeep);
+}
+
+export default clone;

+ 2 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/eq.js

@@ -0,0 +1,2 @@
+import isEqual from './isEqual'
+export default isEqual;

+ 34 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isArguments.js

@@ -0,0 +1,34 @@
+import isArrayLike from '../internal/isArrayLike';
+import isObjectLike from '../internal/isObjectLike';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/** Native method references. */
+var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+
+/**
+ * Checks if `value` is classified as an `arguments` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArguments(function() { return arguments; }());
+ * // => true
+ *
+ * _.isArguments([1, 2, 3]);
+ * // => false
+ */
+function isArguments(value) {
+  return isObjectLike(value) && isArrayLike(value) &&
+    hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
+}
+
+export default isArguments;

+ 48 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isArray.js

@@ -0,0 +1,48 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+import getNative from '../internal/getNative';
+import isLength from '../internal/isLength';
+import isObjectLike from '../internal/isObjectLike';
+
+/** `Object#toString` result references. */
+var arrayTag = '[object Array]';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/* Native method references for those with the same name as other `lodash` methods. */
+var nativeIsArray = getNative(Array, 'isArray');
+
+/**
+ * Checks if `value` is classified as an `Array` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isArray([1, 2, 3]);
+ * // => true
+ *
+ * _.isArray(function() { return arguments; }());
+ * // => false
+ */
+var isArray = nativeIsArray || function(value) {
+  return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
+};
+
+export default isArray;

+ 62 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isEqual.js

@@ -0,0 +1,62 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+import baseIsEqual from '../internal/baseIsEqual';
+import bindCallback from '../internal/bindCallback';
+
+/**
+ * Performs a deep comparison between two values to determine if they are
+ * equivalent. If `customizer` is provided it's invoked to compare values.
+ * If `customizer` returns `undefined` comparisons are handled by the method
+ * instead. The `customizer` is bound to `thisArg` and invoked with up to
+ * three arguments: (value, other [, index|key]).
+ *
+ * **Note:** This method supports comparing arrays, booleans, `Date` objects,
+ * numbers, `Object` objects, regexes, and strings. Objects are compared by
+ * their own, not inherited, enumerable properties. Functions and DOM nodes
+ * are **not** supported. Provide a customizer function to extend support
+ * for comparing other values.
+ *
+ * @static
+ * @memberOf _
+ * @alias eq
+ * @category Lang
+ * @param {*} value The value to compare.
+ * @param {*} other The other value to compare.
+ * @param {Function} [customizer] The function to customize value comparisons.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ * var other = { 'user': 'fred' };
+ *
+ * object == other;
+ * // => false
+ *
+ * _.isEqual(object, other);
+ * // => true
+ *
+ * // using a customizer callback
+ * var array = ['hello', 'goodbye'];
+ * var other = ['hi', 'goodbye'];
+ *
+ * _.isEqual(array, other, function(value, other) {
+ *   if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) {
+ *     return true;
+ *   }
+ * });
+ * // => true
+ */
+function isEqual(value, other, customizer, thisArg) {
+  customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined;
+  var result = customizer ? customizer(value, other) : undefined;
+  return  result === undefined ? baseIsEqual(value, other, customizer) : !!result;
+}
+
+export default isEqual;

+ 38 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isFunction.js

@@ -0,0 +1,38 @@
+import isObject from './isObject';
+
+/** `Object#toString` result references. */
+var funcTag = '[object Function]';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/**
+ * Checks if `value` is classified as a `Function` object.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isFunction(_);
+ * // => true
+ *
+ * _.isFunction(/abc/);
+ * // => false
+ */
+function isFunction(value) {
+  // The use of `Object#toString` avoids issues with the `typeof` operator
+  // in older versions of Chrome and Safari which return 'function' for regexes
+  // and Safari 8 which returns 'object' for typed array constructors.
+  return isObject(value) && objToString.call(value) == funcTag;
+}
+
+export default isFunction;

+ 48 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isNative.js

@@ -0,0 +1,48 @@
+import isFunction from './isFunction';
+import isObjectLike from '../internal/isObjectLike';
+
+/** Used to detect host constructors (Safari > 5). */
+var reIsHostCtor = /^\[object .+?Constructor\]$/;
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to resolve the decompiled source of functions. */
+var fnToString = Function.prototype.toString;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/** Used to detect if a method is native. */
+var reIsNative = RegExp('^' +
+  fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
+  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
+);
+
+/**
+ * Checks if `value` is a native function.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
+ * @example
+ *
+ * _.isNative(Array.prototype.push);
+ * // => true
+ *
+ * _.isNative(_);
+ * // => false
+ */
+function isNative(value) {
+  if (value == null) {
+    return false;
+  }
+  if (isFunction(value)) {
+    return reIsNative.test(fnToString.call(value));
+  }
+  return isObjectLike(value) && reIsHostCtor.test(value);
+}
+
+export default isNative;

+ 37 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isObject.js

@@ -0,0 +1,37 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+
+/**
+ * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
+ * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
+ * @example
+ *
+ * _.isObject({});
+ * // => true
+ *
+ * _.isObject([1, 2, 3]);
+ * // => true
+ *
+ * _.isObject(1);
+ * // => false
+ */
+function isObject(value) {
+  // Avoid a V8 JIT bug in Chrome 19-20.
+  // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+  var type = typeof value;
+  return !!value && (type == 'object' || type == 'function');
+}
+
+export default isObject;

+ 79 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isPlainObject.js

@@ -0,0 +1,79 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+import baseForIn from '../internal/baseForIn';
+import isArguments from './isArguments';
+import isObjectLike from '../internal/isObjectLike';
+
+/** `Object#toString` result references. */
+var objectTag = '[object Object]';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/**
+ * Checks if `value` is a plain object, that is, an object created by the
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
+ *
+ * **Note:** This method assumes objects created by the `Object` constructor
+ * have no inherited enumerable properties.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
+ * @example
+ *
+ * function Foo() {
+ *   this.a = 1;
+ * }
+ *
+ * _.isPlainObject(new Foo);
+ * // => false
+ *
+ * _.isPlainObject([1, 2, 3]);
+ * // => false
+ *
+ * _.isPlainObject({ 'x': 0, 'y': 0 });
+ * // => true
+ *
+ * _.isPlainObject(Object.create(null));
+ * // => true
+ */
+function isPlainObject(value) {
+  var Ctor;
+
+  // Exit early for non `Object` objects.
+  if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) ||
+      (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
+    return false;
+  }
+  // IE < 9 iterates inherited properties before own properties. If the first
+  // iterated property is an object's own property then there are no inherited
+  // enumerable properties.
+  var result;
+  // In most environments an object's own properties are iterated before
+  // its inherited properties. If the last iterated property is an object's
+  // own property then there are no inherited enumerable properties.
+  baseForIn(value, function(subValue, key) {
+    result = key;
+  });
+  return result === undefined || hasOwnProperty.call(value, result);
+}
+
+export default isPlainObject;

+ 74 - 0
packages/ckeditor5-ui/src/lib/lodash/lang/isTypedArray.js

@@ -0,0 +1,74 @@
+import isLength from '../internal/isLength';
+import isObjectLike from '../internal/isObjectLike';
+
+/** `Object#toString` result references. */
+var argsTag = '[object Arguments]',
+    arrayTag = '[object Array]',
+    boolTag = '[object Boolean]',
+    dateTag = '[object Date]',
+    errorTag = '[object Error]',
+    funcTag = '[object Function]',
+    mapTag = '[object Map]',
+    numberTag = '[object Number]',
+    objectTag = '[object Object]',
+    regexpTag = '[object RegExp]',
+    setTag = '[object Set]',
+    stringTag = '[object String]',
+    weakMapTag = '[object WeakMap]';
+
+var arrayBufferTag = '[object ArrayBuffer]',
+    float32Tag = '[object Float32Array]',
+    float64Tag = '[object Float64Array]',
+    int8Tag = '[object Int8Array]',
+    int16Tag = '[object Int16Array]',
+    int32Tag = '[object Int32Array]',
+    uint8Tag = '[object Uint8Array]',
+    uint8ClampedTag = '[object Uint8ClampedArray]',
+    uint16Tag = '[object Uint16Array]',
+    uint32Tag = '[object Uint32Array]';
+
+/** Used to identify `toStringTag` values of typed arrays. */
+var typedArrayTags = {};
+typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
+typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
+typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
+typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
+typedArrayTags[uint32Tag] = true;
+typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
+typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
+typedArrayTags[dateTag] = typedArrayTags[errorTag] =
+typedArrayTags[funcTag] = typedArrayTags[mapTag] =
+typedArrayTags[numberTag] = typedArrayTags[objectTag] =
+typedArrayTags[regexpTag] = typedArrayTags[setTag] =
+typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/**
+ * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
+ * of values.
+ */
+var objToString = objectProto.toString;
+
+/**
+ * Checks if `value` is classified as a typed array.
+ *
+ * @static
+ * @memberOf _
+ * @category Lang
+ * @param {*} value The value to check.
+ * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
+ * @example
+ *
+ * _.isTypedArray(new Uint8Array);
+ * // => true
+ *
+ * _.isTypedArray([]);
+ * // => false
+ */
+function isTypedArray(value) {
+  return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
+}
+
+export default isTypedArray;

+ 0 - 1650
packages/ckeditor5-ui/src/lib/lodash/lodash-ckeditor.js

@@ -1,1650 +0,0 @@
-/**
- * @license
- * lodash 3.10.1 (Custom Build) <https://lodash.com/>
- * Build: `lodash modern exports="amd" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash/lodash-ckeditor.js`
- * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
- * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
- * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
- * Available under MIT license <https://lodash.com/license>
- */
-;(function() {
-
-  /** Used as a safe reference for `undefined` in pre-ES5 environments. */
-  var undefined;
-
-  /** Used as the semantic version number. */
-  var VERSION = '3.10.1';
-
-  /** Used as the `TypeError` message for "Functions" methods. */
-  var FUNC_ERROR_TEXT = 'Expected a function';
-
-  /** `Object#toString` result references. */
-  var argsTag = '[object Arguments]',
-      arrayTag = '[object Array]',
-      boolTag = '[object Boolean]',
-      dateTag = '[object Date]',
-      errorTag = '[object Error]',
-      funcTag = '[object Function]',
-      mapTag = '[object Map]',
-      numberTag = '[object Number]',
-      objectTag = '[object Object]',
-      regexpTag = '[object RegExp]',
-      setTag = '[object Set]',
-      stringTag = '[object String]',
-      weakMapTag = '[object WeakMap]';
-
-  var arrayBufferTag = '[object ArrayBuffer]',
-      float32Tag = '[object Float32Array]',
-      float64Tag = '[object Float64Array]',
-      int8Tag = '[object Int8Array]',
-      int16Tag = '[object Int16Array]',
-      int32Tag = '[object Int32Array]',
-      uint8Tag = '[object Uint8Array]',
-      uint8ClampedTag = '[object Uint8ClampedArray]',
-      uint16Tag = '[object Uint16Array]',
-      uint32Tag = '[object Uint32Array]';
-
-  /** Used to match `RegExp` flags from their coerced string values. */
-  var reFlags = /\w*$/;
-
-  /** Used to detect host constructors (Safari > 5). */
-  var reIsHostCtor = /^\[object .+?Constructor\]$/;
-
-  /** Used to detect unsigned integer values. */
-  var reIsUint = /^\d+$/;
-
-  /** Used to identify `toStringTag` values of typed arrays. */
-  var typedArrayTags = {};
-  typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
-  typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
-  typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
-  typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
-  typedArrayTags[uint32Tag] = true;
-  typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
-  typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
-  typedArrayTags[dateTag] = typedArrayTags[errorTag] =
-  typedArrayTags[funcTag] = typedArrayTags[mapTag] =
-  typedArrayTags[numberTag] = typedArrayTags[objectTag] =
-  typedArrayTags[regexpTag] = typedArrayTags[setTag] =
-  typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false;
-
-  /** Used to identify `toStringTag` values supported by `_.clone`. */
-  var cloneableTags = {};
-  cloneableTags[argsTag] = cloneableTags[arrayTag] =
-  cloneableTags[arrayBufferTag] = cloneableTags[boolTag] =
-  cloneableTags[dateTag] = cloneableTags[float32Tag] =
-  cloneableTags[float64Tag] = cloneableTags[int8Tag] =
-  cloneableTags[int16Tag] = cloneableTags[int32Tag] =
-  cloneableTags[numberTag] = cloneableTags[objectTag] =
-  cloneableTags[regexpTag] = cloneableTags[stringTag] =
-  cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
-  cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
-  cloneableTags[errorTag] = cloneableTags[funcTag] =
-  cloneableTags[mapTag] = cloneableTags[setTag] =
-  cloneableTags[weakMapTag] = false;
-
-  /** Used to determine if values are of the language type `Object`. */
-  var objectTypes = {
-    'function': true,
-    'object': true
-  };
-
-  /** Detect free variable `exports`. */
-  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
-
-  /** Detect free variable `module`. */
-  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
-
-  /** Detect free variable `global` from Node.js. */
-  var freeGlobal = freeExports && freeModule && typeof global == 'object' && global && global.Object && global;
-
-  /** Detect free variable `self`. */
-  var freeSelf = objectTypes[typeof self] && self && self.Object && self;
-
-  /** Detect free variable `window`. */
-  var freeWindow = objectTypes[typeof window] && window && window.Object && window;
-
-  /**
-   * Used as a reference to the global object.
-   *
-   * The `this` value is used if it's the global object to avoid Greasemonkey's
-   * restricted `window` object, otherwise the `window` object is used.
-   */
-  var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || freeSelf || this;
-
-  /*--------------------------------------------------------------------------*/
-
-  /**
-   * Checks if `value` is object-like.
-   *
-   * @private
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
-   */
-  function isObjectLike(value) {
-    return !!value && typeof value == 'object';
-  }
-
-  /*--------------------------------------------------------------------------*/
-
-  /** Used for native method references. */
-  var objectProto = Object.prototype;
-
-  /** Used to resolve the decompiled source of functions. */
-  var fnToString = Function.prototype.toString;
-
-  /** Used to check objects for own properties. */
-  var hasOwnProperty = objectProto.hasOwnProperty;
-
-  /**
-   * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
-   * of values.
-   */
-  var objToString = objectProto.toString;
-
-  /** Used to detect if a method is native. */
-  var reIsNative = RegExp('^' +
-    fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
-    .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-  );
-
-  /** Native method references. */
-  var ArrayBuffer = root.ArrayBuffer,
-      propertyIsEnumerable = objectProto.propertyIsEnumerable,
-      Uint8Array = root.Uint8Array;
-
-  /* Native method references for those with the same name as other `lodash` methods. */
-  var nativeIsArray = getNative(Array, 'isArray'),
-      nativeKeys = getNative(Object, 'keys'),
-      nativeMax = Math.max;
-
-  /**
-   * Used as the [maximum length](http://ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer)
-   * of an array-like value.
-   */
-  var MAX_SAFE_INTEGER = 9007199254740991;
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * Creates a `lodash` object which wraps `value` to enable implicit chaining.
-   * Methods that operate on and return arrays, collections, and functions can
-   * be chained together. Methods that retrieve a single value or may return a
-   * primitive value will automatically end the chain returning the unwrapped
-   * value. Explicit chaining may be enabled using `_.chain`. The execution of
-   * chained methods is lazy, that is, execution is deferred until `_#value`
-   * is implicitly or explicitly called.
-   *
-   * Lazy evaluation allows several methods to support shortcut fusion. Shortcut
-   * fusion is an optimization strategy which merge iteratee calls; this can help
-   * to avoid the creation of intermediate data structures and greatly reduce the
-   * number of iteratee executions.
-   *
-   * Chaining is supported in custom builds as long as the `_#value` method is
-   * directly or indirectly included in the build.
-   *
-   * In addition to lodash methods, wrappers have `Array` and `String` methods.
-   *
-   * The wrapper `Array` methods are:
-   * `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`,
-   * `splice`, and `unshift`
-   *
-   * The wrapper `String` methods are:
-   * `replace` and `split`
-   *
-   * The wrapper methods that support shortcut fusion are:
-   * `compact`, `drop`, `dropRight`, `dropRightWhile`, `dropWhile`, `filter`,
-   * `first`, `initial`, `last`, `map`, `pluck`, `reject`, `rest`, `reverse`,
-   * `slice`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, `toArray`,
-   * and `where`
-   *
-   * The chainable wrapper methods are:
-   * `after`, `ary`, `assign`, `at`, `before`, `bind`, `bindAll`, `bindKey`,
-   * `callback`, `chain`, `chunk`, `commit`, `compact`, `concat`, `constant`,
-   * `countBy`, `create`, `curry`, `debounce`, `defaults`, `defaultsDeep`,
-   * `defer`, `delay`, `difference`, `drop`, `dropRight`, `dropRightWhile`,
-   * `dropWhile`, `fill`, `filter`, `flatten`, `flattenDeep`, `flow`, `flowRight`,
-   * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`,
-   * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`,
-   * `invoke`, `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`,
-   * `matchesProperty`, `memoize`, `merge`, `method`, `methodOf`, `mixin`,
-   * `modArgs`, `negate`, `omit`, `once`, `pairs`, `partial`, `partialRight`,
-   * `partition`, `pick`, `plant`, `pluck`, `property`, `propertyOf`, `pull`,
-   * `pullAt`, `push`, `range`, `rearg`, `reject`, `remove`, `rest`, `restParam`,
-   * `reverse`, `set`, `shuffle`, `slice`, `sort`, `sortBy`, `sortByAll`,
-   * `sortByOrder`, `splice`, `spread`, `take`, `takeRight`, `takeRightWhile`,
-   * `takeWhile`, `tap`, `throttle`, `thru`, `times`, `toArray`, `toPlainObject`,
-   * `transform`, `union`, `uniq`, `unshift`, `unzip`, `unzipWith`, `values`,
-   * `valuesIn`, `where`, `without`, `wrap`, `xor`, `zip`, `zipObject`, `zipWith`
-   *
-   * The wrapper methods that are **not** chainable by default are:
-   * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clone`, `cloneDeep`,
-   * `deburr`, `endsWith`, `escape`, `escapeRegExp`, `every`, `find`, `findIndex`,
-   * `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `findWhere`, `first`,
-   * `floor`, `get`, `gt`, `gte`, `has`, `identity`, `includes`, `indexOf`,
-   * `inRange`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`,
-   * `isEmpty`, `isEqual`, `isError`, `isFinite` `isFunction`, `isMatch`,
-   * `isNative`, `isNaN`, `isNull`, `isNumber`, `isObject`, `isPlainObject`,
-   * `isRegExp`, `isString`, `isUndefined`, `isTypedArray`, `join`, `kebabCase`,
-   * `last`, `lastIndexOf`, `lt`, `lte`, `max`, `min`, `noConflict`, `noop`,
-   * `now`, `pad`, `padLeft`, `padRight`, `parseInt`, `pop`, `random`, `reduce`,
-   * `reduceRight`, `repeat`, `result`, `round`, `runInContext`, `shift`, `size`,
-   * `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`, `startCase`,
-   * `startsWith`, `sum`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
-   * `unescape`, `uniqueId`, `value`, and `words`
-   *
-   * The wrapper method `sample` will return a wrapped value when `n` is provided,
-   * otherwise an unwrapped value is returned.
-   *
-   * @name _
-   * @constructor
-   * @category Chain
-   * @param {*} value The value to wrap in a `lodash` instance.
-   * @returns {Object} Returns the new `lodash` wrapper instance.
-   * @example
-   *
-   * var wrapped = _([1, 2, 3]);
-   *
-   * // returns an unwrapped value
-   * wrapped.reduce(function(total, n) {
-   *   return total + n;
-   * });
-   * // => 6
-   *
-   * // returns a wrapped value
-   * var squares = wrapped.map(function(n) {
-   *   return n * n;
-   * });
-   *
-   * _.isArray(squares);
-   * // => false
-   *
-   * _.isArray(squares.value());
-   * // => true
-   */
-  function lodash() {
-    // No operation performed.
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * Copies the values of `source` to `array`.
-   *
-   * @private
-   * @param {Array} source The array to copy values from.
-   * @param {Array} [array=[]] The array to copy values to.
-   * @returns {Array} Returns `array`.
-   */
-  function arrayCopy(source, array) {
-    var index = -1,
-        length = source.length;
-
-    array || (array = Array(length));
-    while (++index < length) {
-      array[index] = source[index];
-    }
-    return array;
-  }
-
-  /**
-   * A specialized version of `_.forEach` for arrays without support for callback
-   * shorthands and `this` binding.
-   *
-   * @private
-   * @param {Array} array The array to iterate over.
-   * @param {Function} iteratee The function invoked per iteration.
-   * @returns {Array} Returns `array`.
-   */
-  function arrayEach(array, iteratee) {
-    var index = -1,
-        length = array.length;
-
-    while (++index < length) {
-      if (iteratee(array[index], index, array) === false) {
-        break;
-      }
-    }
-    return array;
-  }
-
-  /**
-   * A specialized version of `_.some` for arrays without support for callback
-   * shorthands and `this` binding.
-   *
-   * @private
-   * @param {Array} array The array to iterate over.
-   * @param {Function} predicate The function invoked per iteration.
-   * @returns {boolean} Returns `true` if any element passes the predicate check,
-   *  else `false`.
-   */
-  function arraySome(array, predicate) {
-    var index = -1,
-        length = array.length;
-
-    while (++index < length) {
-      if (predicate(array[index], index, array)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /**
-   * A specialized version of `_.assign` for customizing assigned values without
-   * support for argument juggling, multiple sources, and `this` binding `customizer`
-   * functions.
-   *
-   * @private
-   * @param {Object} object The destination object.
-   * @param {Object} source The source object.
-   * @param {Function} customizer The function to customize assigned values.
-   * @returns {Object} Returns `object`.
-   */
-  function assignWith(object, source, customizer) {
-    var index = -1,
-        props = keys(source),
-        length = props.length;
-
-    while (++index < length) {
-      var key = props[index],
-          value = object[key],
-          result = customizer(value, source[key], key, object, source);
-
-      if ((result === result ? (result !== value) : (value === value)) ||
-          (value === undefined && !(key in object))) {
-        object[key] = result;
-      }
-    }
-    return object;
-  }
-
-  /**
-   * The base implementation of `_.assign` without support for argument juggling,
-   * multiple sources, and `customizer` functions.
-   *
-   * @private
-   * @param {Object} object The destination object.
-   * @param {Object} source The source object.
-   * @returns {Object} Returns `object`.
-   */
-  function baseAssign(object, source) {
-    return source == null
-      ? object
-      : baseCopy(source, keys(source), object);
-  }
-
-  /**
-   * Copies properties of `source` to `object`.
-   *
-   * @private
-   * @param {Object} source The object to copy properties from.
-   * @param {Array} props The property names to copy.
-   * @param {Object} [object={}] The object to copy properties to.
-   * @returns {Object} Returns `object`.
-   */
-  function baseCopy(source, props, object) {
-    object || (object = {});
-
-    var index = -1,
-        length = props.length;
-
-    while (++index < length) {
-      var key = props[index];
-      object[key] = source[key];
-    }
-    return object;
-  }
-
-  /**
-   * The base implementation of `_.clone` without support for argument juggling
-   * and `this` binding `customizer` functions.
-   *
-   * @private
-   * @param {*} value The value to clone.
-   * @param {boolean} [isDeep] Specify a deep clone.
-   * @param {Function} [customizer] The function to customize cloning values.
-   * @param {string} [key] The key of `value`.
-   * @param {Object} [object] The object `value` belongs to.
-   * @param {Array} [stackA=[]] Tracks traversed source objects.
-   * @param {Array} [stackB=[]] Associates clones with source counterparts.
-   * @returns {*} Returns the cloned value.
-   */
-  function baseClone(value, isDeep, customizer, key, object, stackA, stackB) {
-    var result;
-    if (customizer) {
-      result = object ? customizer(value, key, object) : customizer(value);
-    }
-    if (result !== undefined) {
-      return result;
-    }
-    if (!isObject(value)) {
-      return value;
-    }
-    var isArr = isArray(value);
-    if (isArr) {
-      result = initCloneArray(value);
-      if (!isDeep) {
-        return arrayCopy(value, result);
-      }
-    } else {
-      var tag = objToString.call(value),
-          isFunc = tag == funcTag;
-
-      if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
-        result = initCloneObject(isFunc ? {} : value);
-        if (!isDeep) {
-          return baseAssign(result, value);
-        }
-      } else {
-        return cloneableTags[tag]
-          ? initCloneByTag(value, tag, isDeep)
-          : (object ? value : {});
-      }
-    }
-    // Check for circular references and return its corresponding clone.
-    stackA || (stackA = []);
-    stackB || (stackB = []);
-
-    var length = stackA.length;
-    while (length--) {
-      if (stackA[length] == value) {
-        return stackB[length];
-      }
-    }
-    // Add the source value to the stack of traversed objects and associate it with its clone.
-    stackA.push(value);
-    stackB.push(result);
-
-    // Recursively populate clone (susceptible to call stack limits).
-    (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) {
-      result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB);
-    });
-    return result;
-  }
-
-  /**
-   * The base implementation of `baseForIn` and `baseForOwn` which iterates
-   * over `object` properties returned by `keysFunc` invoking `iteratee` for
-   * each property. Iteratee functions may exit iteration early by explicitly
-   * returning `false`.
-   *
-   * @private
-   * @param {Object} object The object to iterate over.
-   * @param {Function} iteratee The function invoked per iteration.
-   * @param {Function} keysFunc The function to get the keys of `object`.
-   * @returns {Object} Returns `object`.
-   */
-  var baseFor = createBaseFor();
-
-  /**
-   * The base implementation of `_.forIn` without support for callback
-   * shorthands and `this` binding.
-   *
-   * @private
-   * @param {Object} object The object to iterate over.
-   * @param {Function} iteratee The function invoked per iteration.
-   * @returns {Object} Returns `object`.
-   */
-  function baseForIn(object, iteratee) {
-    return baseFor(object, iteratee, keysIn);
-  }
-
-  /**
-   * The base implementation of `_.forOwn` without support for callback
-   * shorthands and `this` binding.
-   *
-   * @private
-   * @param {Object} object The object to iterate over.
-   * @param {Function} iteratee The function invoked per iteration.
-   * @returns {Object} Returns `object`.
-   */
-  function baseForOwn(object, iteratee) {
-    return baseFor(object, iteratee, keys);
-  }
-
-  /**
-   * The base implementation of `_.isEqual` without support for `this` binding
-   * `customizer` functions.
-   *
-   * @private
-   * @param {*} value The value to compare.
-   * @param {*} other The other value to compare.
-   * @param {Function} [customizer] The function to customize comparing values.
-   * @param {boolean} [isLoose] Specify performing partial comparisons.
-   * @param {Array} [stackA] Tracks traversed `value` objects.
-   * @param {Array} [stackB] Tracks traversed `other` objects.
-   * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-   */
-  function baseIsEqual(value, other, customizer, isLoose, stackA, stackB) {
-    if (value === other) {
-      return true;
-    }
-    if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
-      return value !== value && other !== other;
-    }
-    return baseIsEqualDeep(value, other, baseIsEqual, customizer, isLoose, stackA, stackB);
-  }
-
-  /**
-   * A specialized version of `baseIsEqual` for arrays and objects which performs
-   * deep comparisons and tracks traversed objects enabling objects with circular
-   * references to be compared.
-   *
-   * @private
-   * @param {Object} object The object to compare.
-   * @param {Object} other The other object to compare.
-   * @param {Function} equalFunc The function to determine equivalents of values.
-   * @param {Function} [customizer] The function to customize comparing objects.
-   * @param {boolean} [isLoose] Specify performing partial comparisons.
-   * @param {Array} [stackA=[]] Tracks traversed `value` objects.
-   * @param {Array} [stackB=[]] Tracks traversed `other` objects.
-   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
-   */
-  function baseIsEqualDeep(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
-    var objIsArr = isArray(object),
-        othIsArr = isArray(other),
-        objTag = arrayTag,
-        othTag = arrayTag;
-
-    if (!objIsArr) {
-      objTag = objToString.call(object);
-      if (objTag == argsTag) {
-        objTag = objectTag;
-      } else if (objTag != objectTag) {
-        objIsArr = isTypedArray(object);
-      }
-    }
-    if (!othIsArr) {
-      othTag = objToString.call(other);
-      if (othTag == argsTag) {
-        othTag = objectTag;
-      } else if (othTag != objectTag) {
-        othIsArr = isTypedArray(other);
-      }
-    }
-    var objIsObj = objTag == objectTag,
-        othIsObj = othTag == objectTag,
-        isSameTag = objTag == othTag;
-
-    if (isSameTag && !(objIsArr || objIsObj)) {
-      return equalByTag(object, other, objTag);
-    }
-    if (!isLoose) {
-      var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
-          othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
-
-      if (objIsWrapped || othIsWrapped) {
-        return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, isLoose, stackA, stackB);
-      }
-    }
-    if (!isSameTag) {
-      return false;
-    }
-    // Assume cyclic values are equal.
-    // For more information on detecting circular references see https://es5.github.io/#JO.
-    stackA || (stackA = []);
-    stackB || (stackB = []);
-
-    var length = stackA.length;
-    while (length--) {
-      if (stackA[length] == object) {
-        return stackB[length] == other;
-      }
-    }
-    // Add `object` and `other` to the stack of traversed objects.
-    stackA.push(object);
-    stackB.push(other);
-
-    var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, isLoose, stackA, stackB);
-
-    stackA.pop();
-    stackB.pop();
-
-    return result;
-  }
-
-  /**
-   * The base implementation of `_.property` without support for deep paths.
-   *
-   * @private
-   * @param {string} key The key of the property to get.
-   * @returns {Function} Returns the new function.
-   */
-  function baseProperty(key) {
-    return function(object) {
-      return object == null ? undefined : object[key];
-    };
-  }
-
-  /**
-   * A specialized version of `baseCallback` which only supports `this` binding
-   * and specifying the number of arguments to provide to `func`.
-   *
-   * @private
-   * @param {Function} func The function to bind.
-   * @param {*} thisArg The `this` binding of `func`.
-   * @param {number} [argCount] The number of arguments to provide to `func`.
-   * @returns {Function} Returns the callback.
-   */
-  function bindCallback(func, thisArg, argCount) {
-    if (typeof func != 'function') {
-      return identity;
-    }
-    if (thisArg === undefined) {
-      return func;
-    }
-    switch (argCount) {
-      case 1: return function(value) {
-        return func.call(thisArg, value);
-      };
-      case 3: return function(value, index, collection) {
-        return func.call(thisArg, value, index, collection);
-      };
-      case 4: return function(accumulator, value, index, collection) {
-        return func.call(thisArg, accumulator, value, index, collection);
-      };
-      case 5: return function(value, other, key, object, source) {
-        return func.call(thisArg, value, other, key, object, source);
-      };
-    }
-    return function() {
-      return func.apply(thisArg, arguments);
-    };
-  }
-
-  /**
-   * Creates a clone of the given array buffer.
-   *
-   * @private
-   * @param {ArrayBuffer} buffer The array buffer to clone.
-   * @returns {ArrayBuffer} Returns the cloned array buffer.
-   */
-  function bufferClone(buffer) {
-    var result = new ArrayBuffer(buffer.byteLength),
-        view = new Uint8Array(result);
-
-    view.set(new Uint8Array(buffer));
-    return result;
-  }
-
-  /**
-   * Creates a `_.assign`, `_.defaults`, or `_.merge` function.
-   *
-   * @private
-   * @param {Function} assigner The function to assign values.
-   * @returns {Function} Returns the new assigner function.
-   */
-  function createAssigner(assigner) {
-    return restParam(function(object, sources) {
-      var index = -1,
-          length = object == null ? 0 : sources.length,
-          customizer = length > 2 ? sources[length - 2] : undefined,
-          guard = length > 2 ? sources[2] : undefined,
-          thisArg = length > 1 ? sources[length - 1] : undefined;
-
-      if (typeof customizer == 'function') {
-        customizer = bindCallback(customizer, thisArg, 5);
-        length -= 2;
-      } else {
-        customizer = typeof thisArg == 'function' ? thisArg : undefined;
-        length -= (customizer ? 1 : 0);
-      }
-      if (guard && isIterateeCall(sources[0], sources[1], guard)) {
-        customizer = length < 3 ? undefined : customizer;
-        length = 1;
-      }
-      while (++index < length) {
-        var source = sources[index];
-        if (source) {
-          assigner(object, source, customizer);
-        }
-      }
-      return object;
-    });
-  }
-
-  /**
-   * Creates a base function for `_.forIn` or `_.forInRight`.
-   *
-   * @private
-   * @param {boolean} [fromRight] Specify iterating from right to left.
-   * @returns {Function} Returns the new base function.
-   */
-  function createBaseFor(fromRight) {
-    return function(object, iteratee, keysFunc) {
-      var iterable = toObject(object),
-          props = keysFunc(object),
-          length = props.length,
-          index = fromRight ? length : -1;
-
-      while ((fromRight ? index-- : ++index < length)) {
-        var key = props[index];
-        if (iteratee(iterable[key], key, iterable) === false) {
-          break;
-        }
-      }
-      return object;
-    };
-  }
-
-  /**
-   * A specialized version of `baseIsEqualDeep` for arrays with support for
-   * partial deep comparisons.
-   *
-   * @private
-   * @param {Array} array The array to compare.
-   * @param {Array} other The other array to compare.
-   * @param {Function} equalFunc The function to determine equivalents of values.
-   * @param {Function} [customizer] The function to customize comparing arrays.
-   * @param {boolean} [isLoose] Specify performing partial comparisons.
-   * @param {Array} [stackA] Tracks traversed `value` objects.
-   * @param {Array} [stackB] Tracks traversed `other` objects.
-   * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
-   */
-  function equalArrays(array, other, equalFunc, customizer, isLoose, stackA, stackB) {
-    var index = -1,
-        arrLength = array.length,
-        othLength = other.length;
-
-    if (arrLength != othLength && !(isLoose && othLength > arrLength)) {
-      return false;
-    }
-    // Ignore non-index properties.
-    while (++index < arrLength) {
-      var arrValue = array[index],
-          othValue = other[index],
-          result = customizer ? customizer(isLoose ? othValue : arrValue, isLoose ? arrValue : othValue, index) : undefined;
-
-      if (result !== undefined) {
-        if (result) {
-          continue;
-        }
-        return false;
-      }
-      // Recursively compare arrays (susceptible to call stack limits).
-      if (isLoose) {
-        if (!arraySome(other, function(othValue) {
-              return arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB);
-            })) {
-          return false;
-        }
-      } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, isLoose, stackA, stackB))) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * A specialized version of `baseIsEqualDeep` for comparing objects of
-   * the same `toStringTag`.
-   *
-   * **Note:** This function only supports comparing values with tags of
-   * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
-   *
-   * @private
-   * @param {Object} object The object to compare.
-   * @param {Object} other The other object to compare.
-   * @param {string} tag The `toStringTag` of the objects to compare.
-   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
-   */
-  function equalByTag(object, other, tag) {
-    switch (tag) {
-      case boolTag:
-      case dateTag:
-        // Coerce dates and booleans to numbers, dates to milliseconds and booleans
-        // to `1` or `0` treating invalid dates coerced to `NaN` as not equal.
-        return +object == +other;
-
-      case errorTag:
-        return object.name == other.name && object.message == other.message;
-
-      case numberTag:
-        // Treat `NaN` vs. `NaN` as equal.
-        return (object != +object)
-          ? other != +other
-          : object == +other;
-
-      case regexpTag:
-      case stringTag:
-        // Coerce regexes to strings and treat strings primitives and string
-        // objects as equal. See https://es5.github.io/#x15.10.6.4 for more details.
-        return object == (other + '');
-    }
-    return false;
-  }
-
-  /**
-   * A specialized version of `baseIsEqualDeep` for objects with support for
-   * partial deep comparisons.
-   *
-   * @private
-   * @param {Object} object The object to compare.
-   * @param {Object} other The other object to compare.
-   * @param {Function} equalFunc The function to determine equivalents of values.
-   * @param {Function} [customizer] The function to customize comparing values.
-   * @param {boolean} [isLoose] Specify performing partial comparisons.
-   * @param {Array} [stackA] Tracks traversed `value` objects.
-   * @param {Array} [stackB] Tracks traversed `other` objects.
-   * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
-   */
-  function equalObjects(object, other, equalFunc, customizer, isLoose, stackA, stackB) {
-    var objProps = keys(object),
-        objLength = objProps.length,
-        othProps = keys(other),
-        othLength = othProps.length;
-
-    if (objLength != othLength && !isLoose) {
-      return false;
-    }
-    var index = objLength;
-    while (index--) {
-      var key = objProps[index];
-      if (!(isLoose ? key in other : hasOwnProperty.call(other, key))) {
-        return false;
-      }
-    }
-    var skipCtor = isLoose;
-    while (++index < objLength) {
-      key = objProps[index];
-      var objValue = object[key],
-          othValue = other[key],
-          result = customizer ? customizer(isLoose ? othValue : objValue, isLoose? objValue : othValue, key) : undefined;
-
-      // Recursively compare objects (susceptible to call stack limits).
-      if (!(result === undefined ? equalFunc(objValue, othValue, customizer, isLoose, stackA, stackB) : result)) {
-        return false;
-      }
-      skipCtor || (skipCtor = key == 'constructor');
-    }
-    if (!skipCtor) {
-      var objCtor = object.constructor,
-          othCtor = other.constructor;
-
-      // Non `Object` object instances with different constructors are not equal.
-      if (objCtor != othCtor &&
-          ('constructor' in object && 'constructor' in other) &&
-          !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
-            typeof othCtor == 'function' && othCtor instanceof othCtor)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  /**
-   * Gets the "length" property value of `object`.
-   *
-   * **Note:** This function is used to avoid a [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792)
-   * that affects Safari on at least iOS 8.1-8.3 ARM64.
-   *
-   * @private
-   * @param {Object} object The object to query.
-   * @returns {*} Returns the "length" value.
-   */
-  var getLength = baseProperty('length');
-
-  /**
-   * Gets the native function at `key` of `object`.
-   *
-   * @private
-   * @param {Object} object The object to query.
-   * @param {string} key The key of the method to get.
-   * @returns {*} Returns the function if it's native, else `undefined`.
-   */
-  function getNative(object, key) {
-    var value = object == null ? undefined : object[key];
-    return isNative(value) ? value : undefined;
-  }
-
-  /**
-   * Initializes an array clone.
-   *
-   * @private
-   * @param {Array} array The array to clone.
-   * @returns {Array} Returns the initialized clone.
-   */
-  function initCloneArray(array) {
-    var length = array.length,
-        result = new array.constructor(length);
-
-    // Add array properties assigned by `RegExp#exec`.
-    if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
-      result.index = array.index;
-      result.input = array.input;
-    }
-    return result;
-  }
-
-  /**
-   * Initializes an object clone.
-   *
-   * @private
-   * @param {Object} object The object to clone.
-   * @returns {Object} Returns the initialized clone.
-   */
-  function initCloneObject(object) {
-    var Ctor = object.constructor;
-    if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) {
-      Ctor = Object;
-    }
-    return new Ctor;
-  }
-
-  /**
-   * Initializes an object clone based on its `toStringTag`.
-   *
-   * **Note:** This function only supports cloning values with tags of
-   * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
-   *
-   * @private
-   * @param {Object} object The object to clone.
-   * @param {string} tag The `toStringTag` of the object to clone.
-   * @param {boolean} [isDeep] Specify a deep clone.
-   * @returns {Object} Returns the initialized clone.
-   */
-  function initCloneByTag(object, tag, isDeep) {
-    var Ctor = object.constructor;
-    switch (tag) {
-      case arrayBufferTag:
-        return bufferClone(object);
-
-      case boolTag:
-      case dateTag:
-        return new Ctor(+object);
-
-      case float32Tag: case float64Tag:
-      case int8Tag: case int16Tag: case int32Tag:
-      case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
-        var buffer = object.buffer;
-        return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length);
-
-      case numberTag:
-      case stringTag:
-        return new Ctor(object);
-
-      case regexpTag:
-        var result = new Ctor(object.source, reFlags.exec(object));
-        result.lastIndex = object.lastIndex;
-    }
-    return result;
-  }
-
-  /**
-   * Checks if `value` is array-like.
-   *
-   * @private
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
-   */
-  function isArrayLike(value) {
-    return value != null && isLength(getLength(value));
-  }
-
-  /**
-   * Checks if `value` is a valid array-like index.
-   *
-   * @private
-   * @param {*} value The value to check.
-   * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
-   * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
-   */
-  function isIndex(value, length) {
-    value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
-    length = length == null ? MAX_SAFE_INTEGER : length;
-    return value > -1 && value % 1 == 0 && value < length;
-  }
-
-  /**
-   * Checks if the provided arguments are from an iteratee call.
-   *
-   * @private
-   * @param {*} value The potential iteratee value argument.
-   * @param {*} index The potential iteratee index or key argument.
-   * @param {*} object The potential iteratee object argument.
-   * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`.
-   */
-  function isIterateeCall(value, index, object) {
-    if (!isObject(object)) {
-      return false;
-    }
-    var type = typeof index;
-    if (type == 'number'
-        ? (isArrayLike(object) && isIndex(index, object.length))
-        : (type == 'string' && index in object)) {
-      var other = object[index];
-      return value === value ? (value === other) : (other !== other);
-    }
-    return false;
-  }
-
-  /**
-   * Checks if `value` is a valid array-like length.
-   *
-   * **Note:** This function is based on [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
-   *
-   * @private
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
-   */
-  function isLength(value) {
-    return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
-  }
-
-  /**
-   * A fallback implementation of `Object.keys` which creates an array of the
-   * own enumerable property names of `object`.
-   *
-   * @private
-   * @param {Object} object The object to query.
-   * @returns {Array} Returns the array of property names.
-   */
-  function shimKeys(object) {
-    var props = keysIn(object),
-        propsLength = props.length,
-        length = propsLength && object.length;
-
-    var allowIndexes = !!length && isLength(length) &&
-      (isArray(object) || isArguments(object));
-
-    var index = -1,
-        result = [];
-
-    while (++index < propsLength) {
-      var key = props[index];
-      if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
-        result.push(key);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Converts `value` to an object if it's not one.
-   *
-   * @private
-   * @param {*} value The value to process.
-   * @returns {Object} Returns the object.
-   */
-  function toObject(value) {
-    return isObject(value) ? value : Object(value);
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * Gets the last element of `array`.
-   *
-   * @static
-   * @memberOf _
-   * @category Array
-   * @param {Array} array The array to query.
-   * @returns {*} Returns the last element of `array`.
-   * @example
-   *
-   * _.last([1, 2, 3]);
-   * // => 3
-   */
-  function last(array) {
-    var length = array ? array.length : 0;
-    return length ? array[length - 1] : undefined;
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * Creates a function that invokes `func` with the `this` binding of the
-   * created function and arguments from `start` and beyond provided as an array.
-   *
-   * **Note:** This method is based on the [rest parameter](https://developer.mozilla.org/Web/JavaScript/Reference/Functions/rest_parameters).
-   *
-   * @static
-   * @memberOf _
-   * @category Function
-   * @param {Function} func The function to apply a rest parameter to.
-   * @param {number} [start=func.length-1] The start position of the rest parameter.
-   * @returns {Function} Returns the new function.
-   * @example
-   *
-   * var say = _.restParam(function(what, names) {
-   *   return what + ' ' + _.initial(names).join(', ') +
-   *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
-   * });
-   *
-   * say('hello', 'fred', 'barney', 'pebbles');
-   * // => 'hello fred, barney, & pebbles'
-   */
-  function restParam(func, start) {
-    if (typeof func != 'function') {
-      throw new TypeError(FUNC_ERROR_TEXT);
-    }
-    start = nativeMax(start === undefined ? (func.length - 1) : (+start || 0), 0);
-    return function() {
-      var args = arguments,
-          index = -1,
-          length = nativeMax(args.length - start, 0),
-          rest = Array(length);
-
-      while (++index < length) {
-        rest[index] = args[start + index];
-      }
-      switch (start) {
-        case 0: return func.call(this, rest);
-        case 1: return func.call(this, args[0], rest);
-        case 2: return func.call(this, args[0], args[1], rest);
-      }
-      var otherArgs = Array(start + 1);
-      index = -1;
-      while (++index < start) {
-        otherArgs[index] = args[index];
-      }
-      otherArgs[start] = rest;
-      return func.apply(this, otherArgs);
-    };
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * Creates a clone of `value`. If `isDeep` is `true` nested objects are cloned,
-   * otherwise they are assigned by reference. If `customizer` is provided it's
-   * invoked to produce the cloned values. If `customizer` returns `undefined`
-   * cloning is handled by the method instead. The `customizer` is bound to
-   * `thisArg` and invoked with up to three argument; (value [, index|key, object]).
-   *
-   * **Note:** This method is loosely based on the
-   * [structured clone algorithm](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm).
-   * The enumerable properties of `arguments` objects and objects created by
-   * constructors other than `Object` are cloned to plain `Object` objects. An
-   * empty object is returned for uncloneable values such as functions, DOM nodes,
-   * Maps, Sets, and WeakMaps.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to clone.
-   * @param {boolean} [isDeep] Specify a deep clone.
-   * @param {Function} [customizer] The function to customize cloning values.
-   * @param {*} [thisArg] The `this` binding of `customizer`.
-   * @returns {*} Returns the cloned value.
-   * @example
-   *
-   * var users = [
-   *   { 'user': 'barney' },
-   *   { 'user': 'fred' }
-   * ];
-   *
-   * var shallow = _.clone(users);
-   * shallow[0] === users[0];
-   * // => true
-   *
-   * var deep = _.clone(users, true);
-   * deep[0] === users[0];
-   * // => false
-   *
-   * // using a customizer callback
-   * var el = _.clone(document.body, function(value) {
-   *   if (_.isElement(value)) {
-   *     return value.cloneNode(false);
-   *   }
-   * });
-   *
-   * el === document.body
-   * // => false
-   * el.nodeName
-   * // => BODY
-   * el.childNodes.length;
-   * // => 0
-   */
-  function clone(value, isDeep, customizer, thisArg) {
-    if (isDeep && typeof isDeep != 'boolean' && isIterateeCall(value, isDeep, customizer)) {
-      isDeep = false;
-    }
-    else if (typeof isDeep == 'function') {
-      thisArg = customizer;
-      customizer = isDeep;
-      isDeep = false;
-    }
-    return typeof customizer == 'function'
-      ? baseClone(value, isDeep, bindCallback(customizer, thisArg, 3))
-      : baseClone(value, isDeep);
-  }
-
-  /**
-   * Checks if `value` is classified as an `arguments` object.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
-   * @example
-   *
-   * _.isArguments(function() { return arguments; }());
-   * // => true
-   *
-   * _.isArguments([1, 2, 3]);
-   * // => false
-   */
-  function isArguments(value) {
-    return isObjectLike(value) && isArrayLike(value) &&
-      hasOwnProperty.call(value, 'callee') && !propertyIsEnumerable.call(value, 'callee');
-  }
-
-  /**
-   * Checks if `value` is classified as an `Array` object.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
-   * @example
-   *
-   * _.isArray([1, 2, 3]);
-   * // => true
-   *
-   * _.isArray(function() { return arguments; }());
-   * // => false
-   */
-  var isArray = nativeIsArray || function(value) {
-    return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag;
-  };
-
-  /**
-   * Performs a deep comparison between two values to determine if they are
-   * equivalent. If `customizer` is provided it's invoked to compare values.
-   * If `customizer` returns `undefined` comparisons are handled by the method
-   * instead. The `customizer` is bound to `thisArg` and invoked with up to
-   * three arguments: (value, other [, index|key]).
-   *
-   * **Note:** This method supports comparing arrays, booleans, `Date` objects,
-   * numbers, `Object` objects, regexes, and strings. Objects are compared by
-   * their own, not inherited, enumerable properties. Functions and DOM nodes
-   * are **not** supported. Provide a customizer function to extend support
-   * for comparing other values.
-   *
-   * @static
-   * @memberOf _
-   * @alias eq
-   * @category Lang
-   * @param {*} value The value to compare.
-   * @param {*} other The other value to compare.
-   * @param {Function} [customizer] The function to customize value comparisons.
-   * @param {*} [thisArg] The `this` binding of `customizer`.
-   * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
-   * @example
-   *
-   * var object = { 'user': 'fred' };
-   * var other = { 'user': 'fred' };
-   *
-   * object == other;
-   * // => false
-   *
-   * _.isEqual(object, other);
-   * // => true
-   *
-   * // using a customizer callback
-   * var array = ['hello', 'goodbye'];
-   * var other = ['hi', 'goodbye'];
-   *
-   * _.isEqual(array, other, function(value, other) {
-   *   if (_.every([value, other], RegExp.prototype.test, /^h(?:i|ello)$/)) {
-   *     return true;
-   *   }
-   * });
-   * // => true
-   */
-  function isEqual(value, other, customizer, thisArg) {
-    customizer = typeof customizer == 'function' ? bindCallback(customizer, thisArg, 3) : undefined;
-    var result = customizer ? customizer(value, other) : undefined;
-    return  result === undefined ? baseIsEqual(value, other, customizer) : !!result;
-  }
-
-  /**
-   * Checks if `value` is classified as a `Function` object.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
-   * @example
-   *
-   * _.isFunction(_);
-   * // => true
-   *
-   * _.isFunction(/abc/);
-   * // => false
-   */
-  function isFunction(value) {
-    // The use of `Object#toString` avoids issues with the `typeof` operator
-    // in older versions of Chrome and Safari which return 'function' for regexes
-    // and Safari 8 which returns 'object' for typed array constructors.
-    return isObject(value) && objToString.call(value) == funcTag;
-  }
-
-  /**
-   * Checks if `value` is the [language type](https://es5.github.io/#x8) of `Object`.
-   * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is an object, else `false`.
-   * @example
-   *
-   * _.isObject({});
-   * // => true
-   *
-   * _.isObject([1, 2, 3]);
-   * // => true
-   *
-   * _.isObject(1);
-   * // => false
-   */
-  function isObject(value) {
-    // Avoid a V8 JIT bug in Chrome 19-20.
-    // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
-    var type = typeof value;
-    return !!value && (type == 'object' || type == 'function');
-  }
-
-  /**
-   * Checks if `value` is a native function.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is a native function, else `false`.
-   * @example
-   *
-   * _.isNative(Array.prototype.push);
-   * // => true
-   *
-   * _.isNative(_);
-   * // => false
-   */
-  function isNative(value) {
-    if (value == null) {
-      return false;
-    }
-    if (isFunction(value)) {
-      return reIsNative.test(fnToString.call(value));
-    }
-    return isObjectLike(value) && reIsHostCtor.test(value);
-  }
-
-  /**
-   * Checks if `value` is a plain object, that is, an object created by the
-   * `Object` constructor or one with a `[[Prototype]]` of `null`.
-   *
-   * **Note:** This method assumes objects created by the `Object` constructor
-   * have no inherited enumerable properties.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
-   * @example
-   *
-   * function Foo() {
-   *   this.a = 1;
-   * }
-   *
-   * _.isPlainObject(new Foo);
-   * // => false
-   *
-   * _.isPlainObject([1, 2, 3]);
-   * // => false
-   *
-   * _.isPlainObject({ 'x': 0, 'y': 0 });
-   * // => true
-   *
-   * _.isPlainObject(Object.create(null));
-   * // => true
-   */
-  function isPlainObject(value) {
-    var Ctor;
-
-    // Exit early for non `Object` objects.
-    if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isArguments(value)) ||
-        (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
-      return false;
-    }
-    // IE < 9 iterates inherited properties before own properties. If the first
-    // iterated property is an object's own property then there are no inherited
-    // enumerable properties.
-    var result;
-    // In most environments an object's own properties are iterated before
-    // its inherited properties. If the last iterated property is an object's
-    // own property then there are no inherited enumerable properties.
-    baseForIn(value, function(subValue, key) {
-      result = key;
-    });
-    return result === undefined || hasOwnProperty.call(value, result);
-  }
-
-  /**
-   * Checks if `value` is classified as a typed array.
-   *
-   * @static
-   * @memberOf _
-   * @category Lang
-   * @param {*} value The value to check.
-   * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
-   * @example
-   *
-   * _.isTypedArray(new Uint8Array);
-   * // => true
-   *
-   * _.isTypedArray([]);
-   * // => false
-   */
-  function isTypedArray(value) {
-    return isObjectLike(value) && isLength(value.length) && !!typedArrayTags[objToString.call(value)];
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * Assigns own enumerable properties of source object(s) to the destination
-   * object. Subsequent sources overwrite property assignments of previous sources.
-   * If `customizer` is provided it's invoked to produce the assigned values.
-   * The `customizer` is bound to `thisArg` and invoked with five arguments:
-   * (objectValue, sourceValue, key, object, source).
-   *
-   * **Note:** This method mutates `object` and is based on
-   * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign).
-   *
-   * @static
-   * @memberOf _
-   * @alias extend
-   * @category Object
-   * @param {Object} object The destination object.
-   * @param {...Object} [sources] The source objects.
-   * @param {Function} [customizer] The function to customize assigned values.
-   * @param {*} [thisArg] The `this` binding of `customizer`.
-   * @returns {Object} Returns `object`.
-   * @example
-   *
-   * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
-   * // => { 'user': 'fred', 'age': 40 }
-   *
-   * // using a customizer callback
-   * var defaults = _.partialRight(_.assign, function(value, other) {
-   *   return _.isUndefined(value) ? other : value;
-   * });
-   *
-   * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
-   * // => { 'user': 'barney', 'age': 36 }
-   */
-  var assign = createAssigner(function(object, source, customizer) {
-    return customizer
-      ? assignWith(object, source, customizer)
-      : baseAssign(object, source);
-  });
-
-  /**
-   * Creates an array of the own enumerable property names of `object`.
-   *
-   * **Note:** Non-object values are coerced to objects. See the
-   * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
-   * for more details.
-   *
-   * @static
-   * @memberOf _
-   * @category Object
-   * @param {Object} object The object to query.
-   * @returns {Array} Returns the array of property names.
-   * @example
-   *
-   * function Foo() {
-   *   this.a = 1;
-   *   this.b = 2;
-   * }
-   *
-   * Foo.prototype.c = 3;
-   *
-   * _.keys(new Foo);
-   * // => ['a', 'b'] (iteration order is not guaranteed)
-   *
-   * _.keys('hi');
-   * // => ['0', '1']
-   */
-  var keys = !nativeKeys ? shimKeys : function(object) {
-    var Ctor = object == null ? undefined : object.constructor;
-    if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
-        (typeof object != 'function' && isArrayLike(object))) {
-      return shimKeys(object);
-    }
-    return isObject(object) ? nativeKeys(object) : [];
-  };
-
-  /**
-   * Creates an array of the own and inherited enumerable property names of `object`.
-   *
-   * **Note:** Non-object values are coerced to objects.
-   *
-   * @static
-   * @memberOf _
-   * @category Object
-   * @param {Object} object The object to query.
-   * @returns {Array} Returns the array of property names.
-   * @example
-   *
-   * function Foo() {
-   *   this.a = 1;
-   *   this.b = 2;
-   * }
-   *
-   * Foo.prototype.c = 3;
-   *
-   * _.keysIn(new Foo);
-   * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
-   */
-  function keysIn(object) {
-    if (object == null) {
-      return [];
-    }
-    if (!isObject(object)) {
-      object = Object(object);
-    }
-    var length = object.length;
-    length = (length && isLength(length) &&
-      (isArray(object) || isArguments(object)) && length) || 0;
-
-    var Ctor = object.constructor,
-        index = -1,
-        isProto = typeof Ctor == 'function' && Ctor.prototype === object,
-        result = Array(length),
-        skipIndexes = length > 0;
-
-    while (++index < length) {
-      result[index] = (index + '');
-    }
-    for (var key in object) {
-      if (!(skipIndexes && isIndex(key, length)) &&
-          !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
-        result.push(key);
-      }
-    }
-    return result;
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * This method returns the first argument provided to it.
-   *
-   * @static
-   * @memberOf _
-   * @category Utility
-   * @param {*} value Any value.
-   * @returns {*} Returns `value`.
-   * @example
-   *
-   * var object = { 'user': 'fred' };
-   *
-   * _.identity(object) === object;
-   * // => true
-   */
-  function identity(value) {
-    return value;
-  }
-
-  /*------------------------------------------------------------------------*/
-
-  // Add functions that return wrapped values when chaining.
-  lodash.assign = assign;
-  lodash.keys = keys;
-  lodash.keysIn = keysIn;
-  lodash.restParam = restParam;
-
-  // Add aliases.
-  lodash.extend = assign;
-
-  /*------------------------------------------------------------------------*/
-
-  // Add functions that return unwrapped values when chaining.
-  lodash.clone = clone;
-  lodash.identity = identity;
-  lodash.isArguments = isArguments;
-  lodash.isArray = isArray;
-  lodash.isEqual = isEqual;
-  lodash.isFunction = isFunction;
-  lodash.isNative = isNative;
-  lodash.isObject = isObject;
-  lodash.isPlainObject = isPlainObject;
-  lodash.isTypedArray = isTypedArray;
-  lodash.last = last;
-
-  // Add aliases.
-  lodash.eq = isEqual;
-
-  /*------------------------------------------------------------------------*/
-
-  /**
-   * The semantic version number.
-   *
-   * @static
-   * @memberOf _
-   * @type string
-   */
-  lodash.VERSION = VERSION;
-
-  /*--------------------------------------------------------------------------*/
-
-  // Some AMD build optimizers like r.js check for condition patterns like the following:
-  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
-    // Define as an anonymous module so, through path mapping, it can be
-    // referenced as the "underscore" module.
-    define(function() {
-      return lodash;
-    });
-  }
-}.call(this));

+ 11 - 0
packages/ckeditor5-ui/src/lib/lodash/object.js

@@ -0,0 +1,11 @@
+import assign from './object/assign';
+import extend from './object/extend';
+import keys from './object/keys';
+import keysIn from './object/keysIn';
+
+export default {
+  'assign': assign,
+  'extend': extend,
+  'keys': keys,
+  'keysIn': keysIn
+};

+ 51 - 0
packages/ckeditor5-ui/src/lib/lodash/object/assign.js

@@ -0,0 +1,51 @@
+/**
+ * lodash 3.10.1 (Custom Build) <https://lodash.com/>
+ * Build: `lodash modularize modern exports="es" include="clone,extend,isPlainObject,isObject,isArray,last,isEqual" --development --output src/lib/lodash`
+ * Copyright 2012-2015 The Dojo Foundation <http://dojofoundation.org/>
+ * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
+ * Copyright 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+ * Available under MIT license <https://lodash.com/license>
+ */
+import assignWith from '../internal/assignWith';
+import baseAssign from '../internal/baseAssign';
+import createAssigner from '../internal/createAssigner';
+
+/**
+ * Assigns own enumerable properties of source object(s) to the destination
+ * object. Subsequent sources overwrite property assignments of previous sources.
+ * If `customizer` is provided it's invoked to produce the assigned values.
+ * The `customizer` is bound to `thisArg` and invoked with five arguments:
+ * (objectValue, sourceValue, key, object, source).
+ *
+ * **Note:** This method mutates `object` and is based on
+ * [`Object.assign`](http://ecma-international.org/ecma-262/6.0/#sec-object.assign).
+ *
+ * @static
+ * @memberOf _
+ * @alias extend
+ * @category Object
+ * @param {Object} object The destination object.
+ * @param {...Object} [sources] The source objects.
+ * @param {Function} [customizer] The function to customize assigned values.
+ * @param {*} [thisArg] The `this` binding of `customizer`.
+ * @returns {Object} Returns `object`.
+ * @example
+ *
+ * _.assign({ 'user': 'barney' }, { 'age': 40 }, { 'user': 'fred' });
+ * // => { 'user': 'fred', 'age': 40 }
+ *
+ * // using a customizer callback
+ * var defaults = _.partialRight(_.assign, function(value, other) {
+ *   return _.isUndefined(value) ? other : value;
+ * });
+ *
+ * defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
+ * // => { 'user': 'barney', 'age': 36 }
+ */
+var assign = createAssigner(function(object, source, customizer) {
+  return customizer
+    ? assignWith(object, source, customizer)
+    : baseAssign(object, source);
+});
+
+export default assign;

+ 2 - 0
packages/ckeditor5-ui/src/lib/lodash/object/extend.js

@@ -0,0 +1,2 @@
+import assign from './assign'
+export default assign;

+ 45 - 0
packages/ckeditor5-ui/src/lib/lodash/object/keys.js

@@ -0,0 +1,45 @@
+import getNative from '../internal/getNative';
+import isArrayLike from '../internal/isArrayLike';
+import isObject from '../lang/isObject';
+import shimKeys from '../internal/shimKeys';
+
+/* Native method references for those with the same name as other `lodash` methods. */
+var nativeKeys = getNative(Object, 'keys');
+
+/**
+ * Creates an array of the own enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects. See the
+ * [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
+ * for more details.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ *   this.a = 1;
+ *   this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keys(new Foo);
+ * // => ['a', 'b'] (iteration order is not guaranteed)
+ *
+ * _.keys('hi');
+ * // => ['0', '1']
+ */
+var keys = !nativeKeys ? shimKeys : function(object) {
+  var Ctor = object == null ? undefined : object.constructor;
+  if ((typeof Ctor == 'function' && Ctor.prototype === object) ||
+      (typeof object != 'function' && isArrayLike(object))) {
+    return shimKeys(object);
+  }
+  return isObject(object) ? nativeKeys(object) : [];
+};
+
+export default keys;

+ 64 - 0
packages/ckeditor5-ui/src/lib/lodash/object/keysIn.js

@@ -0,0 +1,64 @@
+import isArguments from '../lang/isArguments';
+import isArray from '../lang/isArray';
+import isIndex from '../internal/isIndex';
+import isLength from '../internal/isLength';
+import isObject from '../lang/isObject';
+
+/** Used for native method references. */
+var objectProto = Object.prototype;
+
+/** Used to check objects for own properties. */
+var hasOwnProperty = objectProto.hasOwnProperty;
+
+/**
+ * Creates an array of the own and inherited enumerable property names of `object`.
+ *
+ * **Note:** Non-object values are coerced to objects.
+ *
+ * @static
+ * @memberOf _
+ * @category Object
+ * @param {Object} object The object to query.
+ * @returns {Array} Returns the array of property names.
+ * @example
+ *
+ * function Foo() {
+ *   this.a = 1;
+ *   this.b = 2;
+ * }
+ *
+ * Foo.prototype.c = 3;
+ *
+ * _.keysIn(new Foo);
+ * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
+ */
+function keysIn(object) {
+  if (object == null) {
+    return [];
+  }
+  if (!isObject(object)) {
+    object = Object(object);
+  }
+  var length = object.length;
+  length = (length && isLength(length) &&
+    (isArray(object) || isArguments(object)) && length) || 0;
+
+  var Ctor = object.constructor,
+      index = -1,
+      isProto = typeof Ctor == 'function' && Ctor.prototype === object,
+      result = Array(length),
+      skipIndexes = length > 0;
+
+  while (++index < length) {
+    result[index] = (index + '');
+  }
+  for (var key in object) {
+    if (!(skipIndexes && isIndex(key, length)) &&
+        !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
+      result.push(key);
+    }
+  }
+  return result;
+}
+
+export default keysIn;

+ 5 - 0
packages/ckeditor5-ui/src/lib/lodash/utility.js

@@ -0,0 +1,5 @@
+import identity from './utility/identity';
+
+export default {
+  'identity': identity
+};

+ 20 - 0
packages/ckeditor5-ui/src/lib/lodash/utility/identity.js

@@ -0,0 +1,20 @@
+/**
+ * This method returns the first argument provided to it.
+ *
+ * @static
+ * @memberOf _
+ * @category Utility
+ * @param {*} value Any value.
+ * @returns {*} Returns `value`.
+ * @example
+ *
+ * var object = { 'user': 'fred' };
+ *
+ * _.identity(object) === object;
+ * // => true
+ */
+function identity(value) {
+  return value;
+}
+
+export default identity;

+ 29 - 31
packages/ckeditor5-ui/src/log.js

@@ -39,36 +39,34 @@
  * @singleton
  */
 
-CKEDITOR.define( () => {
-	const log = {
-		/**
-		 * Logs an error to the console.
-		 *
-		 * Read more about error logging in the {@link core.log} module.
-		 *
-		 * @param {String} message The error message in an `error-name: Error message.` format.
-		 * During the minification process the "Error message" part will be removed to limit the code size
-		 * and a link to this error documentation will be logged to the console.
-		 * @param {Object} [data] Additional data describing the error.
-		 */
-		error( message, data ) {
-			console.error( message, data );
-		},
+const log = {
+	/**
+	 * Logs an error to the console.
+	 *
+	 * Read more about error logging in the {@link core.log} module.
+	 *
+	 * @param {String} message The error message in an `error-name: Error message.` format.
+	 * During the minification process the "Error message" part will be removed to limit the code size
+	 * and a link to this error documentation will be logged to the console.
+	 * @param {Object} [data] Additional data describing the error.
+	 */
+	error( message, data ) {
+		console.error( message, data );
+	},
 
-		/**
-		 * Logs a warning to the console.
-		 *
-		 * Read more about error logging in the {@link core.log} module.
-		 *
-		 * @param {String} message The warning message in a `warning-name: Warning message.` format.
-		 * During the minification process the "Warning message" part will be removed to limit the code size
-		 * and a link to this error documentation will be logged to the console.
-		 * @param {Object} [data] Additional data describing the warning.
-		 */
-		warn( message, data ) {
-			console.warn( message, data );
-		}
-	};
+	/**
+	 * Logs a warning to the console.
+	 *
+	 * Read more about error logging in the {@link core.log} module.
+	 *
+	 * @param {String} message The warning message in a `warning-name: Warning message.` format.
+	 * During the minification process the "Warning message" part will be removed to limit the code size
+	 * and a link to this error documentation will be logged to the console.
+	 * @param {Object} [data] Additional data describing the warning.
+	 */
+	warn( message, data ) {
+		console.warn( message, data );
+	}
+};
 
-	return log;
-} );
+export default log;

+ 420 - 419
packages/ckeditor5-ui/src/model.js

@@ -12,499 +12,500 @@
  * @mixins EventEmitter
  */
 
-CKEDITOR.define( [ 'emittermixin', 'ckeditorerror', 'utils' ], ( EmitterMixin, CKEditorError, utils ) => {
-	class Model {
+import EmitterMixin from './emittermixin.js';
+import CKEditorError from './ckeditorerror.js';
+import utilsObject from './lib/lodash/object.js';
+import utilsLang from './lib/lodash/lang.js';
+
+export default class Model {
+	/**
+	 * Creates a new Model instance.
+	 *
+	 * @param {Object} [attributes] The model state attributes to be set during the instance creation.
+	 * @param {Object} [properties] The properties to be appended to the instance during creation.
+	 * @method constructor
+	 */
+	constructor( attributes, properties ) {
 		/**
-		 * Creates a new Model instance.
+		 * The internal hash containing the model's state.
 		 *
-		 * @param {Object} [attributes] The model state attributes to be set during the instance creation.
-		 * @param {Object} [properties] The properties to be appended to the instance during creation.
-		 * @method constructor
+		 * @property _attributes
+		 * @private
 		 */
-		constructor( attributes, properties ) {
-			/**
-			 * The internal hash containing the model's state.
-			 *
-			 * @property _attributes
-			 * @private
-			 */
-			this._attributes = {};
-
-			/**
-			 * Map containing bindings of this model to external models.
-			 * See {@link #bind}.
-			 *
-			 * @private
-			 * @property {Map}
-			 */
-			this._boundTo = new Map();
-
-			/**
-			 * Object that stores which attributes of this model are bound.
-			 * See {@link #bind}.
-			 *
-			 * @private
-			 * @property {Object}
-			 */
-			this._bound = {};
-
-			// Extend this instance with the additional (out of state) properties.
-			if ( properties ) {
-				utils.extend( this, properties );
-			}
-
-			// Initialize the attributes.
-			if ( attributes ) {
-				this.set( attributes );
-			}
-		}
+		this._attributes = {};
 
 		/**
-		 * Creates and sets the value of a model attribute of this object. This attribute will be part of the model
-		 * state and will be observable.
-		 *
-		 * It accepts also a single object literal containing key/value pairs with attributes to be set.
-		 *
-		 * This method throws the {@link model-set-cannot-override} error if the model instance already
-		 * have a property with a given attribute name. This prevents from mistakenly overriding existing
-		 * properties and methods, but means that `foo.set( 'bar', 1 )` may be slightly slower than `foo.bar = 1`.
+		 * Map containing bindings of this model to external models.
+		 * See {@link #bind}.
 		 *
-		 * @param {String} name The attributes name.
-		 * @param {*} value The attributes value.
+		 * @private
+		 * @property {Map}
 		 */
-		set( name, value ) {
-			// If the first parameter is an Object, we gonna interact through its properties.
-			if ( utils.isObject( name ) ) {
-				Object.keys( name ).forEach( ( attr ) => {
-					this.set( attr, name[ attr ] );
-				}, this );
-
-				return;
-			}
+		this._boundTo = new Map();
 
-			if ( ( name in this ) && !( name in this._attributes ) ) {
-				/**
-				 * Cannot override an existing property.
-				 *
-				 * This error is thrown when trying to {@link Model#set set} an attribute with
-				 * a name of an already existing property. For example:
-				 *
-				 *		let model = new Model();
-				 *		model.property = 1;
-				 *		model.set( 'property', 2 );		// throws
-				 *
-				 *		model.set( 'attr', 1 );
-				 *		model.set( 'attr', 2 );			// ok, because this is an existing attribute.
-				 *
-				 * @error model-set-cannot-override
-				 */
-				throw new CKEditorError( 'model-set-cannot-override: Cannot override an existing property.' );
-			}
+		/**
+		 * Object that stores which attributes of this model are bound.
+		 * See {@link #bind}.
+		 *
+		 * @private
+		 * @property {Object}
+		 */
+		this._bound = {};
 
-			Object.defineProperty( this, name, {
-				enumerable: true,
-				configurable: true,
+		// Extend this instance with the additional (out of state) properties.
+		if ( properties ) {
+			utilsObject.extend( this, properties );
+		}
 
-				get: () => {
-					return this._attributes[ name ];
-				},
+		// Initialize the attributes.
+		if ( attributes ) {
+			this.set( attributes );
+		}
+	}
 
-				set: ( value ) => {
-					const oldValue = this._attributes[ name ];
+	/**
+	 * Creates and sets the value of a model attribute of this object. This attribute will be part of the model
+	 * state and will be observable.
+	 *
+	 * It accepts also a single object literal containing key/value pairs with attributes to be set.
+	 *
+	 * This method throws the {@link model-set-cannot-override} error if the model instance already
+	 * have a property with a given attribute name. This prevents from mistakenly overriding existing
+	 * properties and methods, but means that `foo.set( 'bar', 1 )` may be slightly slower than `foo.bar = 1`.
+	 *
+	 * @param {String} name The attributes name.
+	 * @param {*} value The attributes value.
+	 */
+	set( name, value ) {
+		// If the first parameter is an Object, we gonna interact through its properties.
+		if ( utilsLang.isObject( name ) ) {
+			Object.keys( name ).forEach( ( attr ) => {
+				this.set( attr, name[ attr ] );
+			}, this );
 
-					if ( oldValue !== value ) {
-						this._attributes[ name ] = value;
-						this.fire( 'change', name, value, oldValue );
-						this.fire( 'change:' + name, value, oldValue );
-					}
-				}
-			} );
+			return;
+		}
 
-			this[ name ] = value;
+		if ( ( name in this ) && !( name in this._attributes ) ) {
+			/**
+			 * Cannot override an existing property.
+			 *
+			 * This error is thrown when trying to {@link Model#set set} an attribute with
+			 * a name of an already existing property. For example:
+			 *
+			 *		let model = new Model();
+			 *		model.property = 1;
+			 *		model.set( 'property', 2 );		// throws
+			 *
+			 *		model.set( 'attr', 1 );
+			 *		model.set( 'attr', 2 );			// ok, because this is an existing attribute.
+			 *
+			 * @error model-set-cannot-override
+			 */
+			throw new CKEditorError( 'model-set-cannot-override: Cannot override an existing property.' );
 		}
 
-		/**
-		 * Binds model attributes to another Model instance.
-		 *
-		 * Once bound, the model will immediately share the current state of attributes
-		 * of the model it is bound to and react to the changes to these attributes
-		 * in the future.
-		 *
-		 * To release the binding use {@link #unbind}.
-		 *
-		 *		A.bind( 'a' ).to( B );
-		 *		A.bind( 'a' ).to( B, 'b' );
-		 *		A.bind( 'a', 'b' ).to( B, 'c', 'd' );
-		 *		A.bind( 'a' ).to( B, 'b' ).to( C, 'd' ).as( ( Bb, Cd ) => Bb + Cd );
-		 *
-		 * @param {String...} bindAttrs Model attributes use that will be bound to another model(s).
-		 * @returns {BindChain}
-		 */
-		bind( ...bindAttrs ) {
-			if ( !bindAttrs.length || !isStringArray( bindAttrs ) ) {
-				/**
-				 * All attributes must be strings.
-				 *
-				 * @error model-bind-wrong-attrs
-				 */
-				throw new CKEditorError( 'model-bind-wrong-attrs: All attributes must be strings.' );
-			}
+		Object.defineProperty( this, name, {
+			enumerable: true,
+			configurable: true,
 
-			if ( ( new Set( bindAttrs ) ).size !== bindAttrs.length ) {
-				/**
-				 * Attributes must be unique.
-				 *
-				 * @error model-bind-duplicate-attrs
-				 */
-				throw new CKEditorError( 'model-bind-duplicate-attrs: Attributes must be unique.' );
-			}
+			get: () => {
+				return this._attributes[ name ];
+			},
 
-			bindAttrs.forEach( attrName => {
-				if ( attrName in this._bound ) {
-					/**
-					 * Cannot bind the same attribute more that once.
-					 *
-					 * @error model-bind-rebind
-					 */
-					throw new CKEditorError( 'model-bind-rebind: Cannot bind the same attribute more that once.' );
+			set: ( value ) => {
+				const oldValue = this._attributes[ name ];
+
+				if ( oldValue !== value ) {
+					this._attributes[ name ] = value;
+					this.fire( 'change', name, value, oldValue );
+					this.fire( 'change:' + name, value, oldValue );
 				}
+			}
+		} );
 
-				this._bound[ attrName ] = true;
-			} );
+		this[ name ] = value;
+	}
 
+	/**
+	 * Binds model attributes to another Model instance.
+	 *
+	 * Once bound, the model will immediately share the current state of attributes
+	 * of the model it is bound to and react to the changes to these attributes
+	 * in the future.
+	 *
+	 * To release the binding use {@link #unbind}.
+	 *
+	 *		A.bind( 'a' ).to( B );
+	 *		A.bind( 'a' ).to( B, 'b' );
+	 *		A.bind( 'a', 'b' ).to( B, 'c', 'd' );
+	 *		A.bind( 'a' ).to( B, 'b' ).to( C, 'd' ).as( ( Bb, Cd ) => Bb + Cd );
+	 *
+	 * @param {String...} bindAttrs Model attributes use that will be bound to another model(s).
+	 * @returns {BindChain}
+	 */
+	bind( ...bindAttrs ) {
+		if ( !bindAttrs.length || !isStringArray( bindAttrs ) ) {
 			/**
-			 * @typedef BindChain
-			 * @type Object
-			 * @property {Model} _bindModel The model which initializes the binding.
-			 * @property {Array} _bindAttrs Array of `_bindModel` attributes to be bound.
-			 * @property {Array} _boundTo Array of `to()` model–attributes (`{ model: toModel, attrs: ...toAttrs }`).
-			 * @property {Object} _current The arguments of the last `to( toModel, ...toAttrs )` call, also
-			 * the last item of `_boundTo`.
-			 * @property {Function} to See {@link #_bindTo}.
-			 * @property {Function} as See {@link #_bindAs} (available after `to()` called in chain).
+			 * All attributes must be strings.
+			 *
+			 * @error model-bind-wrong-attrs
 			 */
-			return {
-				_bindModel: this,
-				_bindAttrs: bindAttrs,
-				_boundTo: [],
-				get _current() {
-					return this._boundTo[ this._boundTo.length - 1 ];
-				},
-				to: this._bindTo
-			};
+			throw new CKEditorError( 'model-bind-wrong-attrs: All attributes must be strings.' );
 		}
 
-		/**
-		 * Removes the binding created with {@link #bind}.
-		 *
-		 *		A.unbind( 'a' );
-		 *		A.unbind();
-		 *
-		 * @param {String...} [bindAttrs] Model attributes to unbound. All the bindings will
-		 * be released if not attributes provided.
-		 */
-		unbind( ...unbindAttrs ) {
-			if ( unbindAttrs.length ) {
-				if ( !isStringArray( unbindAttrs ) ) {
-					/**
-					 * Attributes must be strings.
-					 *
-					 * @error model-unbind-wrong-attrs
-					 */
-					throw new CKEditorError( 'model-unbind-wrong-attrs: Attributes must be strings.' );
-				}
-
-				unbindAttrs.forEach( attrName => {
-					for ( let to of this._boundTo ) {
-						// TODO, ES6 destructuring.
-						const boundModel = to[ 0 ];
-						const bindings = to[ 1 ];
-
-						for ( let boundAttrName in bindings ) {
-							if ( bindings[ boundAttrName ].has( attrName ) ) {
-								bindings[ boundAttrName ].delete( attrName );
-							}
-
-							if ( !bindings[ boundAttrName ].size ) {
-								delete bindings[ boundAttrName ];
-							}
-
-							if ( !Object.keys( bindings ).length ) {
-								this._boundTo.delete( boundModel );
-								this.stopListening( boundModel, 'change' );
-							}
-						}
-					}
-
-					delete this._bound[ attrName ];
-				} );
-			} else {
-				this._boundTo.forEach( ( bindings, boundModel ) => {
-					this.stopListening( boundModel, 'change' );
-					this._boundTo.delete( boundModel );
-				} );
-
-				this._bound = {};
-			}
+		if ( ( new Set( bindAttrs ) ).size !== bindAttrs.length ) {
+			/**
+			 * Attributes must be unique.
+			 *
+			 * @error model-bind-duplicate-attrs
+			 */
+			throw new CKEditorError( 'model-bind-duplicate-attrs: Attributes must be unique.' );
 		}
 
-		/**
-		 * A chaining for {@link #bind} providing `.to()` interface.
-		 *
-		 * @protected
-		 * @param {Model} model A model used for binding.
-		 * @param {String...} [toAttrs] Attributes of the model used for binding.
-		 * @returns {BindChain}
-		 */
-		_bindTo( toModel, ...toAttrs ) {
-			if ( !toModel || !( toModel instanceof Model ) ) {
+		bindAttrs.forEach( attrName => {
+			if ( attrName in this._bound ) {
 				/**
-				 * An instance of Model is required.
+				 * Cannot bind the same attribute more that once.
 				 *
-				 * @error model-bind-to-wrong-model
+				 * @error model-bind-rebind
 				 */
-				throw new CKEditorError( 'model-bind-to-wrong-model: An instance of Model is required.' );
+				throw new CKEditorError( 'model-bind-rebind: Cannot bind the same attribute more that once.' );
 			}
 
-			if ( !isStringArray( toAttrs ) ) {
-				/**
-				 * Model attributes must be strings.
-				 *
-				 * @error model-bind-to-wrong-attrs
-				 */
-				throw new CKEditorError( 'model-bind-to-wrong-attrs: Model attributes must be strings.' );
-			}
+			this._bound[ attrName ] = true;
+		} );
 
-			// Eliminate A.bind( 'x' ).to( B, 'y', 'z' )
-			// Eliminate A.bind( 'x', 'y' ).to( B, 'z' )
-			if ( toAttrs.length && toAttrs.length !== this._bindAttrs.length ) {
-				/**
-				 * The number of attributes must match.
-				 *
-				 * @error model-bind-to-attrs-length
-				 */
-				throw new CKEditorError( 'model-bind-to-attrs-length: The number of attributes must match.' );
-			}
+		/**
+		 * @typedef BindChain
+		 * @type Object
+		 * @property {Model} _bindModel The model which initializes the binding.
+		 * @property {Array} _bindAttrs Array of `_bindModel` attributes to be bound.
+		 * @property {Array} _boundTo Array of `to()` model–attributes (`{ model: toModel, attrs: ...toAttrs }`).
+		 * @property {Object} _current The arguments of the last `to( toModel, ...toAttrs )` call, also
+		 * the last item of `_boundTo`.
+		 * @property {Function} to See {@link #_bindTo}.
+		 * @property {Function} as See {@link #_bindAs} (available after `to()` called in chain).
+		 */
+		return {
+			_bindModel: this,
+			_bindAttrs: bindAttrs,
+			_boundTo: [],
+			get _current() {
+				return this._boundTo[ this._boundTo.length - 1 ];
+			},
+			to: this._bindTo
+		};
+	}
 
-			// Eliminate A.bind( 'x' ).to( B, 'y' ), when B.y == undefined.
-			// Eliminate A.bind( 'x' ).to( B ), when B.x == undefined.
-			if ( !hasAttributes( toModel, toAttrs ) || ( !toAttrs.length && !hasAttributes( toModel, this._bindAttrs ) ) ) {
+	/**
+	 * Removes the binding created with {@link #bind}.
+	 *
+	 *		A.unbind( 'a' );
+	 *		A.unbind();
+	 *
+	 * @param {String...} [bindAttrs] Model attributes to unbound. All the bindings will
+	 * be released if not attributes provided.
+	 */
+	unbind( ...unbindAttrs ) {
+		if ( unbindAttrs.length ) {
+			if ( !isStringArray( unbindAttrs ) ) {
 				/**
-				 * Model has no such attribute(s).
+				 * Attributes must be strings.
 				 *
-				 * @error model-bind-to-missing-attr
+				 * @error model-unbind-wrong-attrs
 				 */
-				throw new CKEditorError( 'model-bind-to-missing-attr: Model has no such attribute(s).' );
+				throw new CKEditorError( 'model-unbind-wrong-attrs: Attributes must be strings.' );
 			}
 
-			// Eliminate A.bind( 'x', 'y' ).to( B ).to( C ) when no trailing .as().
-			// Eliminate A.bind( 'x', 'y' ).to( B, 'x', 'y' ).to( C, 'x', 'y' ).
-			if ( this._boundTo.length && ( toAttrs.length > 1 || this._bindAttrs.length > 1 ) ) {
-				/**
-				 * Chaining only allowed for a single attribute.
-				 *
-				 * @error model-bind-to-chain-multiple-attrs
-				 */
-				throw new CKEditorError( 'model-bind-to-chain-multiple-attrs: Chaining only allowed for a single attribute.' );
-			}
+			unbindAttrs.forEach( attrName => {
+				for ( let to of this._boundTo ) {
+					// TODO, ES6 destructuring.
+					const boundModel = to[ 0 ];
+					const bindings = to[ 1 ];
 
-			// When no toAttrs specified, observing MODEL attributes, like MODEL.bind( 'foo' ).to( TOMODEL )
-			if ( !toAttrs.length ) {
-				toAttrs = this._bindAttrs;
-			}
-
-			// Extend current chain with the new binding information.
-			this._boundTo.push( { model: toModel, attrs: toAttrs } );
-
-			setupBinding( this );
-
-			if ( !this.as ) {
-				this.as = this._bindModel._bindAs;
-			}
+					for ( let boundAttrName in bindings ) {
+						if ( bindings[ boundAttrName ].has( attrName ) ) {
+							bindings[ boundAttrName ].delete( attrName );
+						}
 
-			return this;
-		}
+						if ( !bindings[ boundAttrName ].size ) {
+							delete bindings[ boundAttrName ];
+						}
 
-		/**
-		 * A chaining for {@link #bind} providing `.as()` interface.
-		 *
-		 * @protected
-		 * @param {Function} callback A callback to combine model's attributes.
-		 */
-		_bindAs( callback ) {
-			if ( !callback || typeof callback !== 'function' ) {
-				/**
-				 * Callback must be a Function.
-				 *
-				 * @error model-bind-as-wrong-callback
-				 */
-				throw new CKEditorError( 'model-bind-as-wrong-callback: Callback must be a Function.' );
-			}
+						if ( !Object.keys( bindings ).length ) {
+							this._boundTo.delete( boundModel );
+							this.stopListening( boundModel, 'change' );
+						}
+					}
+				}
 
-			this._callback = callback;
+				delete this._bound[ attrName ];
+			} );
+		} else {
+			this._boundTo.forEach( ( bindings, boundModel ) => {
+				this.stopListening( boundModel, 'change' );
+				this._boundTo.delete( boundModel );
+			} );
 
-			updateModelAttrs( this, this._bindAttrs[ 0 ] );
+			this._bound = {};
 		}
 	}
 
 	/**
-	 * Check if the `model` has given `attrs`.
+	 * A chaining for {@link #bind} providing `.to()` interface.
 	 *
-	 * @private
-	 * @param {Model} model Model to be checked.
-	 * @param {Array} arr An array of `String`.
-	 * @returns {Boolean}
+	 * @protected
+	 * @param {Model} model A model used for binding.
+	 * @param {String...} [toAttrs] Attributes of the model used for binding.
+	 * @returns {BindChain}
 	 */
-	function hasAttributes( model, attrs ) {
-		return attrs.every( a => a in model._attributes );
-	}
+	_bindTo( toModel, ...toAttrs ) {
+		if ( !toModel || !( toModel instanceof Model ) ) {
+			/**
+			 * An instance of Model is required.
+			 *
+			 * @error model-bind-to-wrong-model
+			 */
+			throw new CKEditorError( 'model-bind-to-wrong-model: An instance of Model is required.' );
+		}
 
-	/**
-	 * Check if all entries of the array are of `String` type.
-	 *
-	 * @private
-	 * @param {Array} arr An array to be checked.
-	 * @returns {Boolean}
-	 */
-	function isStringArray( arr ) {
-		return arr.every( a => typeof a == 'string' );
-	}
+		if ( !isStringArray( toAttrs ) ) {
+			/**
+			 * Model attributes must be strings.
+			 *
+			 * @error model-bind-to-wrong-attrs
+			 */
+			throw new CKEditorError( 'model-bind-to-wrong-attrs: Model attributes must be strings.' );
+		}
 
-	/**
-	 * Returns all bindings of the `chain._bindModel` to `chain._current.model`
-	 * set by {@link #updateModelBindingsToCurrent}.
-	 *
-	 *		// Given that A == _bindModel and B == _current.model
-	 *		A.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );
-	 *
-	 *		// The following object is returned
-	 *		{ x: [ 'a', 'c' ], y: [ 'b' ] }
-	 *
-	 *
-	 * @private
-	 * @param {BindChain} chain The chain initialized by {@link Model#bind}.
-	 * @returns {Object}
-	 */
-	function getModelBindingsToCurrent( chain ) {
-		return chain._bindModel._boundTo.get( chain._current.model );
-	}
+		// Eliminate A.bind( 'x' ).to( B, 'y', 'z' )
+		// Eliminate A.bind( 'x', 'y' ).to( B, 'z' )
+		if ( toAttrs.length && toAttrs.length !== this._bindAttrs.length ) {
+			/**
+			 * The number of attributes must match.
+			 *
+			 * @error model-bind-to-attrs-length
+			 */
+			throw new CKEditorError( 'model-bind-to-attrs-length: The number of attributes must match.' );
+		}
 
-	/**
-	 * Updates `chain._bindModel._boundTo` with a binding for `chain._current`.
-	 * The binding can be then retrieved by {@link #getModelBindingsToCurrent}.
-	 *
-	 * @private
-	 * @param {BindChain} chain The chain initialized by {@link Model#bind}.
-	 * @returns {Object}
-	 */
-	function updateModelBindingsToCurrent( chain ) {
-		const currentBindings = getModelBindingsToCurrent( chain );
-		const bindings = currentBindings || {};
+		// Eliminate A.bind( 'x' ).to( B, 'y' ), when B.y == undefined.
+		// Eliminate A.bind( 'x' ).to( B ), when B.x == undefined.
+		if ( !hasAttributes( toModel, toAttrs ) || ( !toAttrs.length && !hasAttributes( toModel, this._bindAttrs ) ) ) {
+			/**
+			 * Model has no such attribute(s).
+			 *
+			 * @error model-bind-to-missing-attr
+			 */
+			throw new CKEditorError( 'model-bind-to-missing-attr: Model has no such attribute(s).' );
+		}
 
-		chain._current.attrs.forEach( ( attrName, index ) => {
-			( bindings[ attrName ] || ( bindings[ attrName ] = new Set() ) )
-				.add( chain._bindAttrs[ index ] );
-		} );
+		// Eliminate A.bind( 'x', 'y' ).to( B ).to( C ) when no trailing .as().
+		// Eliminate A.bind( 'x', 'y' ).to( B, 'x', 'y' ).to( C, 'x', 'y' ).
+		if ( this._boundTo.length && ( toAttrs.length > 1 || this._bindAttrs.length > 1 ) ) {
+			/**
+			 * Chaining only allowed for a single attribute.
+			 *
+			 * @error model-bind-to-chain-multiple-attrs
+			 */
+			throw new CKEditorError( 'model-bind-to-chain-multiple-attrs: Chaining only allowed for a single attribute.' );
+		}
+
+		// When no toAttrs specified, observing MODEL attributes, like MODEL.bind( 'foo' ).to( TOMODEL )
+		if ( !toAttrs.length ) {
+			toAttrs = this._bindAttrs;
+		}
+
+		// Extend current chain with the new binding information.
+		this._boundTo.push( { model: toModel, attrs: toAttrs } );
 
-		if ( !currentBindings ) {
-			chain._bindModel._boundTo.set( chain._current.model, bindings );
+		setupBinding( this );
+
+		if ( !this.as ) {
+			this.as = this._bindModel._bindAs;
 		}
+
+		return this;
 	}
 
 	/**
-	 * Updates the model attribute with given value. If an attribute does not exist,
-	 * it is created on the fly.
+	 * A chaining for {@link #bind} providing `.as()` interface.
 	 *
-	 * @private
-	 * @param {Model} model The model which attribute is updated.
-	 * @param {String} attrName The name of the attribute.
-	 * @param {*} value The value of the attribute.
+	 * @protected
+	 * @param {Function} callback A callback to combine model's attributes.
 	 */
-	function updateModelAttr( model, attrName, value ) {
-		if ( model[ attrName ] ) {
-			model[ attrName ] = value;
-		} else {
-			model.set( attrName, value );
+	_bindAs( callback ) {
+		if ( !callback || typeof callback !== 'function' ) {
+			/**
+			 * Callback must be a Function.
+			 *
+			 * @error model-bind-as-wrong-callback
+			 */
+			throw new CKEditorError( 'model-bind-as-wrong-callback: Callback must be a Function.' );
 		}
+
+		this._callback = callback;
+
+		updateModelAttrs( this, this._bindAttrs[ 0 ] );
 	}
+}
 
-	/**
-	 * Updates all bound attributes of `chain._bindModel` with the `value` of
-	 * `attrName` of `chain._current` model.
-	 *
-	 *		// Given that A == _bindModel and B == _current.model
-	 *		A.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );
-	 *
-	 *		// The following is updated
-	 *		A.a = A.c = B.x;
-	 *		A.b = B.y;
-	 *
-	 * @private
-	 * @param {BindChain} chain The chain initialized by {@link Model#bind}.
-	 * @param {String} attrName One of the attributes of `chain._current`.
-	 * @param {*} value The value of the attribute.
-	 */
-	function updateModelAttrs( chain, attrName, value ) {
-		const boundAttrs = getModelBindingsToCurrent( chain )[ attrName ];
+/**
+ * Check if the `model` has given `attrs`.
+ *
+ * @private
+ * @param {Model} model Model to be checked.
+ * @param {Array} arr An array of `String`.
+ * @returns {Boolean}
+ */
+function hasAttributes( model, attrs ) {
+	return attrs.every( a => a in model._attributes );
+}
 
-		if ( !boundAttrs ) {
-			return;
-		} else if ( chain._callback ) {
-			// MODEL.bind( 'a' ).to( TOMODEL1, 'b1' )[ .to( TOMODELn, 'bn' ) ].as( callback )
-			//  \-> Collect specific attribute value in the boundTo.model (TOMODELn.bn).
-			//
-			// MODEL.bind( 'a' ).to( TOMODEL1 )[ .to( TOMODELn ) ].as( callback )
-			//  \-> Use model attribute name to collect boundTo attribute value (TOMODELn.a).
-			const values = chain._boundTo.map( boundTo => boundTo.model[ boundTo.attrs[ 0 ] ] );
-
-			// Pass collected attribute values to the callback function.
-			// Whatever is returned it becomes the value of the model's attribute.
-			updateModelAttr(
-				chain._bindModel,
-				chain._bindAttrs[ 0 ],
-				chain._callback.apply( chain._bindModel, values )
-			);
-		} else {
-			// MODEL.bind( 'a' ).to( TOMODEL1 )[ .to( TOMODELn ) ];
-			//  \-> If multiple .to() models but **no** .as( callback ), then the binding is invalid.
-			if ( !chain._callback && chain._boundTo.length > 1 ) {
-				value = undefined;
-			}
+/**
+ * Check if all entries of the array are of `String` type.
+ *
+ * @private
+ * @param {Array} arr An array to be checked.
+ * @returns {Boolean}
+ */
+function isStringArray( arr ) {
+	return arr.every( a => typeof a == 'string' );
+}
 
-			for ( let boundAttrName of boundAttrs ) {
-				updateModelAttr( chain._bindModel, boundAttrName, value );
-			}
-		}
+/**
+ * Returns all bindings of the `chain._bindModel` to `chain._current.model`
+ * set by {@link #updateModelBindingsToCurrent}.
+ *
+ *		// Given that A == _bindModel and B == _current.model
+ *		A.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );
+ *
+ *		// The following object is returned
+ *		{ x: [ 'a', 'c' ], y: [ 'b' ] }
+ *
+ *
+ * @private
+ * @param {BindChain} chain The chain initialized by {@link Model#bind}.
+ * @returns {Object}
+ */
+function getModelBindingsToCurrent( chain ) {
+	return chain._bindModel._boundTo.get( chain._current.model );
+}
+
+/**
+ * Updates `chain._bindModel._boundTo` with a binding for `chain._current`.
+ * The binding can be then retrieved by {@link #getModelBindingsToCurrent}.
+ *
+ * @private
+ * @param {BindChain} chain The chain initialized by {@link Model#bind}.
+ * @returns {Object}
+ */
+function updateModelBindingsToCurrent( chain ) {
+	const currentBindings = getModelBindingsToCurrent( chain );
+	const bindings = currentBindings || {};
+
+	chain._current.attrs.forEach( ( attrName, index ) => {
+		( bindings[ attrName ] || ( bindings[ attrName ] = new Set() ) )
+			.add( chain._bindAttrs[ index ] );
+	} );
+
+	if ( !currentBindings ) {
+		chain._bindModel._boundTo.set( chain._current.model, bindings );
 	}
+}
 
-	/**
-	 * Starts listening to changes in `chain._current.model` to update `chain._bindModel`
-	 * attributes. Also sets the initial state of `chain._bindModel` bound attributes.
-	 *
-	 * @private
-	 * @param {BindChain} chain The chain initialized by {@link Model#bind}.
-	 */
-	function setupBinding( chain ) {
-		// If there's already a binding between the models (`chain._bindModel` listens to
-		// `chain._current.model`), there's no need to create another `change` event listener.
-		if ( !getModelBindingsToCurrent( chain ) ) {
-			chain._bindModel.listenTo( chain._current.model, 'change', ( evt, attrName, value ) => {
-				updateModelAttrs( chain, attrName, value );
-			} );
+/**
+ * Updates the model attribute with given value. If an attribute does not exist,
+ * it is created on the fly.
+ *
+ * @private
+ * @param {Model} model The model which attribute is updated.
+ * @param {String} attrName The name of the attribute.
+ * @param {*} value The value of the attribute.
+ */
+function updateModelAttr( model, attrName, value ) {
+	if ( model[ attrName ] ) {
+		model[ attrName ] = value;
+	} else {
+		model.set( attrName, value );
+	}
+}
+
+/**
+ * Updates all bound attributes of `chain._bindModel` with the `value` of
+ * `attrName` of `chain._current` model.
+ *
+ *		// Given that A == _bindModel and B == _current.model
+ *		A.bind( 'a', 'b', 'c' ).to( B, 'x', 'y', 'x' );
+ *
+ *		// The following is updated
+ *		A.a = A.c = B.x;
+ *		A.b = B.y;
+ *
+ * @private
+ * @param {BindChain} chain The chain initialized by {@link Model#bind}.
+ * @param {String} attrName One of the attributes of `chain._current`.
+ * @param {*} value The value of the attribute.
+ */
+function updateModelAttrs( chain, attrName, value ) {
+	const boundAttrs = getModelBindingsToCurrent( chain )[ attrName ];
+
+	if ( !boundAttrs ) {
+		return;
+	} else if ( chain._callback ) {
+		// MODEL.bind( 'a' ).to( TOMODEL1, 'b1' )[ .to( TOMODELn, 'bn' ) ].as( callback )
+		//  \-> Collect specific attribute value in the boundTo.model (TOMODELn.bn).
+		//
+		// MODEL.bind( 'a' ).to( TOMODEL1 )[ .to( TOMODELn ) ].as( callback )
+		//  \-> Use model attribute name to collect boundTo attribute value (TOMODELn.a).
+		const values = chain._boundTo.map( boundTo => boundTo.model[ boundTo.attrs[ 0 ] ] );
+
+		// Pass collected attribute values to the callback function.
+		// Whatever is returned it becomes the value of the model's attribute.
+		updateModelAttr(
+			chain._bindModel,
+			chain._bindAttrs[ 0 ],
+			chain._callback.apply( chain._bindModel, values )
+		);
+	} else {
+		// MODEL.bind( 'a' ).to( TOMODEL1 )[ .to( TOMODELn ) ];
+		//  \-> If multiple .to() models but **no** .as( callback ), then the binding is invalid.
+		if ( !chain._callback && chain._boundTo.length > 1 ) {
+			value = undefined;
 		}
 
-		updateModelBindingsToCurrent( chain );
+		for ( let boundAttrName of boundAttrs ) {
+			updateModelAttr( chain._bindModel, boundAttrName, value );
+		}
+	}
+}
 
-		// Set initial model state.
-		chain._current.attrs.forEach( attrName => {
-			updateModelAttrs( chain, attrName, chain._current.model[ attrName ] );
+/**
+ * Starts listening to changes in `chain._current.model` to update `chain._bindModel`
+ * attributes. Also sets the initial state of `chain._bindModel` bound attributes.
+ *
+ * @private
+ * @param {BindChain} chain The chain initialized by {@link Model#bind}.
+ */
+function setupBinding( chain ) {
+	// If there's already a binding between the models (`chain._bindModel` listens to
+	// `chain._current.model`), there's no need to create another `change` event listener.
+	if ( !getModelBindingsToCurrent( chain ) ) {
+		chain._bindModel.listenTo( chain._current.model, 'change', ( evt, attrName, value ) => {
+			updateModelAttrs( chain, attrName, value );
 		} );
 	}
 
-	utils.extend( Model.prototype, EmitterMixin );
+	updateModelBindingsToCurrent( chain );
+
+	// Set initial model state.
+	chain._current.attrs.forEach( attrName => {
+		updateModelAttrs( chain, attrName, chain._current.model[ attrName ] );
+	} );
+}
 
-	return Model;
-} );
+utilsObject.extend( Model.prototype, EmitterMixin );
 
 /**
  * Fired when an attribute changed value.

+ 0 - 86
packages/ckeditor5-ui/src/utils-lodash.js

@@ -1,86 +0,0 @@
-/**
- * @license Copyright (c) 2003-2015, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* globals module */
-
-'use strict';
-
-// This module returns the list of Lo-Dash methods that will be exported to the main "utils" module. It is coded in a
-// way that it can be used by the CKEditor core code in "utils" as well as from Node.js with the configurations for
-// `grunt lodash`.
-//
-// https://lodash.com/docs
-
-( () => {
-	// The list of Lo-Dash methods to include in "utils".
-	// It is mandatory to execute `grunt lodash` after changes to this list.
-	const lodashInclude = [
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#clone
-		 *
-		 * @member utils
-		 * @method clone
-		 */
-		'clone',
-
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#assign (alias)
-		 *
-		 * @member utils
-		 * @method extend
-		 */
-		'extend',
-
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#isPlainObject
-		 *
-		 * @member utils
-		 * @method isPlainObject
-		 */
-		'isPlainObject',
-
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#isObject
-		 *
-		 * @member utils
-		 * @method isObject
-		 */
-		'isObject',
-
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#isArray
-		 *
-		 * @member utils
-		 * @method isArray
-		 */
-		'isArray',
-
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#last
-		 *
-		 * @member utils
-		 * @method last
-		 */
-		'last',
-
-		/**
-		 * See Lo-Dash: https://lodash.com/docs#isEqual
-		 *
-		 * @member utils
-		 * @method isEqual
-		 */
-		'isEqual'
-	];
-
-	// Make this compatible with CommonJS as well so it can be used in Node (e.g. "grunt lodash").
-	/* istanbul ignore next: we're not able to test the following in bender so ignore it */
-	if ( typeof module == 'object' && module.exports ) {
-		module.exports = lodashInclude;
-	} else {
-		CKEDITOR.define( () => {
-			return lodashInclude;
-		} );
-	}
-} )();

+ 103 - 121
packages/ckeditor5-ui/src/utils.js

@@ -6,138 +6,120 @@
 'use strict';
 
 /**
- * A utilities library.
+ * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.
  *
- * @class utils
- * @singleton
+ * The following are the present features:
+ *
+ *  * spy.called: property set to `true` if the function has been called at least once.
+ *
+ * @returns {Function} The spy function.
  */
+export function spy() {
+	return function spy() {
+		spy.called = true;
+	};
+}
 
-CKEDITOR.define( [ 'utils-lodash', 'lib/lodash/lodash-ckeditor' ], ( lodashIncludes, lodash ) => {
-	const utils = {
-		/**
-		 * Creates a spy function (ala Sinon.js) that can be used to inspect call to it.
-		 *
-		 * The following are the present features:
-		 *
-		 *  * spy.called: property set to `true` if the function has been called at least once.
-		 *
-		 * @returns {Function} The spy function.
-		 */
-		spy() {
-			return function spy() {
-				spy.called = true;
-			};
-		},
-
-		/**
-		 * Returns a unique id. This id is a number (starting from 1) which will never get repeated on successive calls
-		 * to this method.
-		 *
-		 * @returns {Number} A number representing the id.
-		 */
-		uid: ( () => {
-			let next = 1;
-
-			return () => {
-				return next++;
-			};
-		} )(),
+/**
+ * Returns a unique id. This id is a number (starting from 1) which will never get repeated on successive calls
+ * to this method.
+ *
+ * @returns {Number} A number representing the id.
+ */
+export let uid = ( () => {
+	let next = 1;
 
-		/**
-		 * Checks if value implements iterator interface.
-		 *
-		 * @param {Mixed} value The value to check.
-		 * @returns {Boolean} True if value implements iterator interface.
-		 */
-		isIterable( value ) {
-			return !!( value && value[ Symbol.iterator ] );
-		},
+	return () => {
+		return next++;
+	};
+} )();
 
-		/**
-		 * Compares how given arrays relate to each other. One array can be: same as another array, prefix of another array
-		 * or completely different. If arrays are different, first index at which they differ is returned. Otherwise,
-		 * a flag specifying the relation is returned. Flags are negative numbers, so whenever a number >= 0 is returned
-		 * it means that arrays differ.
-		 *
-		 *   compareArrays( [ 0, 2 ], [ 0, 2 ] ); // SAME
-		 *   compareArrays( [ 0, 2 ], [ 0, 2, 1 ] ); // PREFIX
-		 *   compareArrays( [ 0, 2 ], [ 0 ] ); // EXTENSION
-		 *   compareArrays( [ 0, 2 ], [ 1, 2 ] ); // 0
-		 *   compareArrays( [ 0, 2 ], [ 0, 1 ] ); // 1
-		 *
-		 * @param {Array} a Array that is compared.
-		 * @param {Array} b Array to compare with.
-		 * @returns {Number} An index at which arrays differ, or if they do not differ, how array `a` is related to array `b`.
-		 * This is represented by one of flags: `a` is {@link utils.compareArrays#SAME same}, `a` is
-		 * a {@link utils.compareArrays#PREFIX prefix) or `a` is an {@link utils.compareArrays#EXTENSION extension}.
-		 */
-		compareArrays( a, b ) {
-			const minLen = Math.min( a.length, b.length );
+/**
+ * Checks if value implements iterator interface.
+ *
+ * @param {Mixed} value The value to check.
+ * @returns {Boolean} True if value implements iterator interface.
+ */
+export function isIterable( value ) {
+	return !!( value && value[ Symbol.iterator ] );
+}
 
-			for ( let i = 0; i < minLen; i++ ) {
-				if ( a[ i ] != b[ i ] ) {
-					// The arrays are different.
-					return i;
-				}
-			}
+/**
+ * Compares how given arrays relate to each other. One array can be: same as another array, prefix of another array
+ * or completely different. If arrays are different, first index at which they differ is returned. Otherwise,
+ * a flag specifying the relation is returned. Flags are negative numbers, so whenever a number >= 0 is returned
+ * it means that arrays differ.
+ *
+ *   compareArrays( [ 0, 2 ], [ 0, 2 ] ); // SAME
+ *   compareArrays( [ 0, 2 ], [ 0, 2, 1 ] ); // PREFIX
+ *   compareArrays( [ 0, 2 ], [ 0 ] ); // EXTENSION
+ *   compareArrays( [ 0, 2 ], [ 1, 2 ] ); // 0
+ *   compareArrays( [ 0, 2 ], [ 0, 1 ] ); // 1
+ *
+ * @param {Array} a Array that is compared.
+ * @param {Array} b Array to compare with.
+ * @returns {Number} An index at which arrays differ, or if they do not differ, how array `a` is related to array `b`.
+ * This is represented by one of flags: `a` is {@link utils.compareArrays#SAME same}, `a` is
+ * a {@link utils.compareArrays#PREFIX prefix) or `a` is an {@link utils.compareArrays#EXTENSION extension}.
+ */
+export function compareArrays( a, b ) {
+	const minLen = Math.min( a.length, b.length );
 
-			// Both arrays were same at all points.
-			if ( a.length == b.length ) {
-				// If their length is also same, they are the same.
-				return utils.compareArrays.SAME;
-			} else if ( a.length < b.length ) {
-				// Compared array is shorter so it is a prefix of the other array.
-				return utils.compareArrays.PREFIX;
-			} else {
-				// Compared array is longer so it is an extension of the other array.
-				return utils.compareArrays.EXTENSION;
-			}
-		},
+	for ( let i = 0; i < minLen; i++ ) {
+		if ( a[ i ] != b[ i ] ) {
+			// The arrays are different.
+			return i;
+		}
+	}
 
-		/**
-		 * Returns `nth` (starts from `0` of course) item of an `iterable`.
-		 *
-		 * @param {Number} index
-		 * @param {Iterable.<*>} iterable
-		 * @returns {*}
-		 */
-		nth( index, iterable ) {
-			for ( let item of iterable ) {
-				if ( index === 0 ) {
-					return item;
-				}
-				index -= 1;
-			}
+	// Both arrays were same at all points.
+	if ( a.length == b.length ) {
+		// If their length is also same, they are the same.
+		return compareArrays.SAME;
+	} else if ( a.length < b.length ) {
+		// Compared array is shorter so it is a prefix of the other array.
+		return compareArrays.PREFIX;
+	} else {
+		// Compared array is longer so it is an extension of the other array.
+		return compareArrays.EXTENSION;
+	}
+}
 
-			return null;
+/**
+ * Returns `nth` (starts from `0` of course) item of an `iterable`.
+ *
+ * @param {Number} index
+ * @param {Iterable.<*>} iterable
+ * @returns {*}
+ */
+export function nth( index, iterable ) {
+	for ( let item of iterable ) {
+		if ( index === 0 ) {
+			return item;
 		}
-	};
-
-	/**
-	 * Flag for "is same as" relation between arrays.
-	 *
-	 * @type {Number}
-	 */
-	utils.compareArrays.SAME = -1;
+		index -= 1;
+	}
 
-	/**
-	 * Flag for "is a prefix of" relation between arrays.
-	 *
-	 * @type {Number}
-	 */
-	utils.compareArrays.PREFIX = -2;
+	return null;
+}
 
-	/**
-	 * Flag for "is a suffix of" relation between arrays.
-	 *
-	 * @type {number}
-	 */
-	utils.compareArrays.EXTENSION = -3;
+/**
+ * Flag for "is same as" relation between arrays.
+ *
+ * @type {Number}
+ */
+compareArrays.SAME = -1;
 
-	// Extend "utils" with Lo-Dash methods.
-	for ( let i = 0; i < lodashIncludes.length; i++ ) {
-		utils[ lodashIncludes[ i ] ] = lodash[ lodashIncludes[ i ] ];
-	}
+/**
+ * Flag for "is a prefix of" relation between arrays.
+ *
+ * @type {Number}
+ */
+compareArrays.PREFIX = -2;
 
-	return utils;
-} );
+/**
+ * Flag for "is a suffix of" relation between arrays.
+ *
+ * @type {number}
+ */
+compareArrays.EXTENSION = -3;

+ 9 - 28
packages/ckeditor5-ui/tests/mvc/model/model.js → packages/ckeditor5-ui/tests/model.js

@@ -5,16 +5,22 @@
 
 'use strict';
 
-const modules = bender.amd.require( 'model', 'eventinfo', 'ckeditorerror' );
+const modules = bender.amd.require( 'core/model', 'core/eventinfo', 'core/ckeditorerror' );
 
 let Car, car;
 
 bender.tools.createSinonSandbox();
 
 describe( 'Model', () => {
-	beforeEach( 'Create a test model instance', () => {
-		const Model = modules.model;
+	let Model, EventInfo, CKEditorError;
+
+	before( () => {
+		Model = modules[ 'core/model' ];
+		EventInfo = modules[ 'core/eventinfo' ];
+		CKEditorError = modules[ 'core/ckeditorerror' ];
+	} );
 
+	beforeEach( 'Create a test model instance', () => {
 		Car = class extends Model {};
 
 		car = new Car( {
@@ -83,8 +89,6 @@ describe( 'Model', () => {
 		} );
 
 		it( 'should fire the "change" event', () => {
-			const EventInfo = modules.eventinfo;
-
 			let spy = sinon.spy();
 			let spyColor = sinon.spy();
 			let spyYear = sinon.spy();
@@ -138,8 +142,6 @@ describe( 'Model', () => {
 		} );
 
 		it( 'should throw when overriding already existing property', () => {
-			const CKEditorError = modules.ckeditorerror;
-
 			car.normalProperty = 1;
 
 			expect( () => {
@@ -150,9 +152,6 @@ describe( 'Model', () => {
 		} );
 
 		it( 'should throw when overriding already existing property (in the prototype)', () => {
-			const CKEditorError = modules.ckeditorerror;
-			const Model = modules.model;
-
 			class Car extends Model {
 				method() {}
 			}
@@ -169,8 +168,6 @@ describe( 'Model', () => {
 
 	describe( 'extend', () => {
 		it( 'should create new Model based classes', () => {
-			const Model = modules.model;
-
 			class Truck extends Car {}
 
 			let truck = new Truck();
@@ -181,14 +178,6 @@ describe( 'Model', () => {
 	} );
 
 	describe( 'bind', () => {
-		let Model, EventInfo, CKEditorError;
-
-		beforeEach( () => {
-			Model = modules.model;
-			EventInfo = modules.eventinfo;
-			CKEditorError = modules.ckeditorerror;
-		} );
-
 		it( 'should chain for a single attribute', () => {
 			expect( car.bind( 'color' ) ).to.contain.keys( 'to' );
 		} );
@@ -536,14 +525,6 @@ describe( 'Model', () => {
 	} );
 
 	describe( 'unbind', () => {
-		let Model, EventInfo, CKEditorError;
-
-		beforeEach( () => {
-			Model = modules.model;
-			EventInfo = modules.eventinfo;
-			CKEditorError = modules.ckeditorerror;
-		} );
-
 		it( 'should throw when non-string attribute is passed', () => {
 			expect( () => {
 				car.unbind( new Date() );

+ 1 - 1
packages/ckeditor5-ui/tests/ui/controller.js

@@ -3,7 +3,7 @@
  * For licensing, see LICENSE.md.
  */
 
-/* bender-tags: core, ui */
+/* bender-tags: ui */
 
 'use strict';
 

+ 1 - 1
packages/ckeditor5-ui/tests/ui/controllercollection.js

@@ -3,7 +3,7 @@
  * For licensing, see LICENSE.md.
  */
 
-/* bender-tags: core, ui */
+/* bender-tags: ui */
 
 'use strict';
 

+ 1 - 1
packages/ckeditor5-ui/tests/ui/domemittermixin.js

@@ -4,7 +4,7 @@
  */
 
 /* global document, Event, MouseEvent */
-/* bender-tags: core, ui */
+/* bender-tags: ui */
 
 'use strict';
 

+ 1 - 1
packages/ckeditor5-ui/tests/ui/region.js

@@ -4,7 +4,7 @@
  */
 
 /* global document */
-/* bender-tags: core, ui */
+/* bender-tags: ui */
 
 'use strict';
 

+ 1 - 1
packages/ckeditor5-ui/tests/ui/template.js

@@ -3,7 +3,7 @@
  * For licensing, see LICENSE.md.
  */
 
-/* bender-tags: core, ui */
+/* bender-tags: ui */
 /* global HTMLElement */
 
 'use strict';

+ 1 - 1
packages/ckeditor5-ui/tests/ui/view.js

@@ -4,7 +4,7 @@
  */
 
 /* global document, HTMLElement */
-/* bender-tags: core, ui */
+/* bender-tags: ui */
 
 'use strict';