Merge branch 'MDL-56826-master-fix1' of git://github.com/damyon/moodle
authorDavid Monllao <davidm@moodle.com>
Thu, 17 Nov 2016 12:25:31 +0000 (20:25 +0800)
committerDavid Monllao <davidm@moodle.com>
Thu, 17 Nov 2016 12:25:31 +0000 (20:25 +0800)
21 files changed:
admin/tool/lpmigrate/tests/processor_test.php
blocks/login/block_login.php
media/player/videojs/amd/build/Youtube.min.js
media/player/videojs/amd/build/video.min.js
media/player/videojs/amd/src/Youtube.js
media/player/videojs/amd/src/video.js
media/player/videojs/classes/plugin.php
media/player/videojs/readme_moodle.txt
media/player/videojs/styles.css
media/player/videojs/thirdpartylibs.xml
media/player/videojs/videojs/lang/de.js
media/player/videojs/videojs/lang/el.js
media/player/videojs/videojs/lang/en.js
media/player/videojs/videojs/lang/fr.js
media/player/videojs/videojs/video-js.swf [moved from media/player/videojs/video-js.swf with 100% similarity]
message/output/airnotifier/message_output_airnotifier.php
message/output/airnotifier/style.css [deleted file]
message/output/airnotifier/yui/build/moodle-message_airnotifier-toolboxes/moodle-message_airnotifier-toolboxes-debug.js
message/output/airnotifier/yui/build/moodle-message_airnotifier-toolboxes/moodle-message_airnotifier-toolboxes-min.js
message/output/airnotifier/yui/build/moodle-message_airnotifier-toolboxes/moodle-message_airnotifier-toolboxes.js
message/output/airnotifier/yui/src/toolboxes/js/toolboxes.js

index 792a902..78eb45b 100644 (file)
@@ -396,12 +396,8 @@ class tool_lpmigrate_framework_processor_testcase extends advanced_testcase {
     }
 
     public function test_permission_exception() {
-        global $DB;
-        if ($DB->get_dbfamily() === 'postgres' or $DB->get_dbfamily() === 'mssql') {
-            $this->markTestSkipped('The processor is having issues with the transaction initialised in '
-                . 'advanced_testcase::runBare().');
-            return;
-        }
+
+        $this->preventResetByRollback(); // Test uses transactions, so we cannot use them for speedy reset.
 
         $dg = $this->getDataGenerator();
         $u = $dg->create_user();
index 5699ba6..26ca859 100644 (file)
@@ -87,9 +87,11 @@ class block_login extends block_base {
 
             if (isset($CFG->rememberusername) and $CFG->rememberusername == 2) {
                 $checked = $username ? 'checked="checked"' : '';
-                $this->content->text .= '<div class="form-check-inline">';
-                $this->content->text .= '<input type="checkbox" name="rememberusername" id="rememberusername" class="form-check-input" value="1" '.$checked.'/>';
-                $this->content->text .= ' <label for="rememberusername" class="form-check-label">'.get_string('rememberusername', 'admin').'</label>';
+                $this->content->text .= '<div class="form-check">';
+                $this->content->text .= '<label class="form-check-label">';
+                $this->content->text .= '<input type="checkbox" name="rememberusername" id="rememberusername"
+                        class="form-check-input" value="1" '.$checked.'/> ';
+                $this->content->text .= get_string('rememberusername', 'admin').'</label>';
                 $this->content->text .= '</div>';
             }
 
index 87d11c8..785b901 100644 (file)
Binary files a/media/player/videojs/amd/build/Youtube.min.js and b/media/player/videojs/amd/build/Youtube.min.js differ
index 3d94e7f..6692d51 100644 (file)
Binary files a/media/player/videojs/amd/build/video.min.js and b/media/player/videojs/amd/build/video.min.js differ
index c4c8c4d..c2391da 100644 (file)
@@ -77,7 +77,7 @@ THE SOFTWARE. */
       this.el_.parentNode.className = this.el_.parentNode.className
         .replace(' vjs-youtube', '')
         .replace(' vjs-youtube-mobile', '');
-      this.el_.parentNode.removeChild(this.el_);
+      this.el_.remove();
 
       //Needs to be called after the YouTube player is destroyed, otherwise there will be a null reference exception
       Tech.prototype.dispose.call(this);
index e8d2b12..258cd06 100644 (file)
@@ -1,6 +1,6 @@
 /**
  * @license
- * Video.js 5.11.8 <http://videojs.com/>
+ * Video.js 5.12.6 <http://videojs.com/>
  * Copyright Brightcove, Inc. <https://www.brightcove.com/>
  * Available under Apache License Version 2.0
  * <https://github.com/videojs/video.js/blob/master/LICENSE>
  */
 
 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojs = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
-(function (global){
-var topLevel = typeof global !== 'undefined' ? global :
-    typeof window !== 'undefined' ? window : {}
-var minDoc = _dereq_('min-document');
+'use strict';
 
-if (typeof document !== 'undefined') {
-    module.exports = document;
-} else {
-    var doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
+exports.__esModule = true;
 
-    if (!doccy) {
-        doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
-    }
+var _button = _dereq_(2);
 
-    module.exports = doccy;
-}
+var _button2 = _interopRequireDefault(_button);
 
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9nbG9iYWwvZG9jdW1lbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyJ2YXIgdG9wTGV2ZWwgPSB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6XG4gICAgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB7fVxudmFyIG1pbkRvYyA9IHJlcXVpcmUoJ21pbi1kb2N1bWVudCcpO1xuXG5pZiAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJykge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZG9jdW1lbnQ7XG59IGVsc2Uge1xuICAgIHZhciBkb2NjeSA9IHRvcExldmVsWydfX0dMT0JBTF9ET0NVTUVOVF9DQUNIRUA0J107XG5cbiAgICBpZiAoIWRvY2N5KSB7XG4gICAgICAgIGRvY2N5ID0gdG9wTGV2ZWxbJ19fR0xPQkFMX0RPQ1VNRU5UX0NBQ0hFQDQnXSA9IG1pbkRvYztcbiAgICB9XG5cbiAgICBtb2R1bGUuZXhwb3J0cyA9IGRvY2N5O1xufVxuIl19
-},{"min-document":3}],2:[function(_dereq_,module,exports){
-(function (global){
-if (typeof window !== "undefined") {
-    module.exports = window;
-} else if (typeof global !== "undefined") {
-    module.exports = global;
-} else if (typeof self !== "undefined"){
-    module.exports = self;
-} else {
-    module.exports = {};
-}
+var _component = _dereq_(5);
 
-}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9nbG9iYWwvd2luZG93LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiaWYgKHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHdpbmRvdztcbn0gZWxzZSBpZiAodHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZ2xvYmFsO1xufSBlbHNlIGlmICh0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIil7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBzZWxmO1xufSBlbHNlIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHt9O1xufVxuIl19
-},{}],3:[function(_dereq_,module,exports){
+var _component2 = _interopRequireDefault(_component);
 
-},{}],4:[function(_dereq_,module,exports){
-var getNative = _dereq_('../internal/getNative');
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file big-play-button.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-/* Native method references for those with the same name as other `lodash` methods. */
-var nativeNow = getNative(Date, 'now');
 
 /**
- * Gets the number of milliseconds that have elapsed since the Unix epoch
- * (1 January 1970 00:00:00 UTC).
- *
- * @static
- * @memberOf _
- * @category Date
- * @example
+ * Initial play button. Shows before the video has played. The hiding of the
+ * big play button is done via CSS and player states.
  *
- * _.defer(function(stamp) {
- *   console.log(_.now() - stamp);
- * }, _.now());
- * // => logs the number of milliseconds it took for the deferred function to be invoked
+ * @param {Object} player  Main Player
+ * @param {Object=} options Object of option names and values
+ * @extends Button
+ * @class BigPlayButton
  */
-var now = nativeNow || function() {
-  return new Date().getTime();
-};
+var BigPlayButton = function (_Button) {
+  _inherits(BigPlayButton, _Button);
 
-module.exports = now;
+  function BigPlayButton(player, options) {
+    _classCallCheck(this, BigPlayButton);
 
-},{"../internal/getNative":20}],5:[function(_dereq_,module,exports){
-var isObject = _dereq_('../lang/isObject'),
-    now = _dereq_('../date/now');
+    return _possibleConstructorReturn(this, _Button.call(this, player, options));
+  }
 
-/** Used as the `TypeError` message for "Functions" methods. */
-var FUNC_ERROR_TEXT = 'Expected a function';
+  /**
+   * Allow sub components to stack CSS class names
+   *
+   * @return {String} The constructed class name
+   * @method buildCSSClass
+   */
 
-/* Native method references for those with the same name as other `lodash` methods. */
-var nativeMax = Math.max;
 
-/**
- * Creates a debounced function that delays invoking `func` until after `wait`
- * milliseconds have elapsed since the last time the debounced function was
- * invoked. The debounced function comes with a `cancel` method to cancel
- * delayed invocations. Provide an options object to indicate that `func`
- * should be invoked on the leading and/or trailing edge of the `wait` timeout.
- * Subsequent calls to the debounced function return the result of the last
- * `func` invocation.
- *
- * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
- * on the trailing edge of the timeout only if the the debounced function is
- * invoked more than once during the `wait` timeout.
- *
- * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
- * for details over the differences between `_.debounce` and `_.throttle`.
- *
- * @static
- * @memberOf _
- * @category Function
- * @param {Function} func The function to debounce.
- * @param {number} [wait=0] The number of milliseconds to delay.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.leading=false] Specify invoking on the leading
- *  edge of the timeout.
- * @param {number} [options.maxWait] The maximum time `func` is allowed to be
- *  delayed before it's invoked.
- * @param {boolean} [options.trailing=true] Specify invoking on the trailing
- *  edge of the timeout.
- * @returns {Function} Returns the new debounced function.
- * @example
- *
- * // avoid costly calculations while the window size is in flux
- * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
- *
- * // invoke `sendMail` when the click event is fired, debouncing subsequent calls
- * jQuery('#postbox').on('click', _.debounce(sendMail, 300, {
- *   'leading': true,
- *   'trailing': false
- * }));
- *
- * // ensure `batchLog` is invoked once after 1 second of debounced calls
- * var source = new EventSource('/stream');
- * jQuery(source).on('message', _.debounce(batchLog, 250, {
- *   'maxWait': 1000
- * }));
- *
- * // cancel a debounced call
- * var todoChanges = _.debounce(batchLog, 1000);
- * Object.observe(models.todo, todoChanges);
- *
- * Object.observe(models, function(changes) {
- *   if (_.find(changes, { 'user': 'todo', 'type': 'delete'})) {
- *     todoChanges.cancel();
- *   }
- * }, ['delete']);
- *
- * // ...at some point `models.todo` is changed
- * models.todo.completed = true;
- *
- * // ...before 1 second has passed `models.todo` is deleted
- * // which cancels the debounced `todoChanges` call
- * delete models.todo;
- */
-function debounce(func, wait, options) {
-  var args,
-      maxTimeoutId,
-      result,
-      stamp,
-      thisArg,
-      timeoutId,
-      trailingCall,
-      lastCalled = 0,
-      maxWait = false,
-      trailing = true;
+  BigPlayButton.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-big-play-button';
+  };
 
-  if (typeof func != 'function') {
-    throw new TypeError(FUNC_ERROR_TEXT);
-  }
-  wait = wait < 0 ? 0 : (+wait || 0);
-  if (options === true) {
-    var leading = true;
-    trailing = false;
-  } else if (isObject(options)) {
-    leading = !!options.leading;
-    maxWait = 'maxWait' in options && nativeMax(+options.maxWait || 0, wait);
-    trailing = 'trailing' in options ? !!options.trailing : trailing;
-  }
+  /**
+   * Handles click for play
+   *
+   * @method handleClick
+   */
 
-  function cancel() {
-    if (timeoutId) {
-      clearTimeout(timeoutId);
-    }
-    if (maxTimeoutId) {
-      clearTimeout(maxTimeoutId);
-    }
-    lastCalled = 0;
-    maxTimeoutId = timeoutId = trailingCall = undefined;
-  }
 
-  function complete(isCalled, id) {
-    if (id) {
-      clearTimeout(id);
-    }
-    maxTimeoutId = timeoutId = trailingCall = undefined;
-    if (isCalled) {
-      lastCalled = now();
-      result = func.apply(thisArg, args);
-      if (!timeoutId && !maxTimeoutId) {
-        args = thisArg = undefined;
-      }
-    }
-  }
+  BigPlayButton.prototype.handleClick = function handleClick() {
+    this.player_.play();
+  };
 
-  function delayed() {
-    var remaining = wait - (now() - stamp);
-    if (remaining <= 0 || remaining > wait) {
-      complete(trailingCall, maxTimeoutId);
-    } else {
-      timeoutId = setTimeout(delayed, remaining);
-    }
-  }
+  return BigPlayButton;
+}(_button2['default']);
 
-  function maxDelayed() {
-    complete(trailing, timeoutId);
-  }
+BigPlayButton.prototype.controlText_ = 'Play Video';
 
-  function debounced() {
-    args = arguments;
-    stamp = now();
-    thisArg = this;
-    trailingCall = trailing && (timeoutId || !leading);
+_component2['default'].registerComponent('BigPlayButton', BigPlayButton);
+exports['default'] = BigPlayButton;
 
-    if (maxWait === false) {
-      var leadingCall = leading && !timeoutId;
-    } else {
-      if (!maxTimeoutId && !leading) {
-        lastCalled = stamp;
-      }
-      var remaining = maxWait - (stamp - lastCalled),
-          isCalled = remaining <= 0 || remaining > maxWait;
+},{"2":2,"5":5}],2:[function(_dereq_,module,exports){
+'use strict';
 
-      if (isCalled) {
-        if (maxTimeoutId) {
-          maxTimeoutId = clearTimeout(maxTimeoutId);
-        }
-        lastCalled = stamp;
-        result = func.apply(thisArg, args);
-      }
-      else if (!maxTimeoutId) {
-        maxTimeoutId = setTimeout(maxDelayed, remaining);
-      }
-    }
-    if (isCalled && timeoutId) {
-      timeoutId = clearTimeout(timeoutId);
-    }
-    else if (!timeoutId && wait !== maxWait) {
-      timeoutId = setTimeout(delayed, wait);
-    }
-    if (leadingCall) {
-      isCalled = true;
-      result = func.apply(thisArg, args);
-    }
-    if (isCalled && !timeoutId && !maxTimeoutId) {
-      args = thisArg = undefined;
-    }
-    return result;
-  }
-  debounced.cancel = cancel;
-  return debounced;
-}
+exports.__esModule = true;
 
-module.exports = debounce;
+var _clickableComponent = _dereq_(3);
 
-},{"../date/now":4,"../lang/isObject":33}],6:[function(_dereq_,module,exports){
-/** Used as the `TypeError` message for "Functions" methods. */
-var FUNC_ERROR_TEXT = 'Expected a function';
+var _clickableComponent2 = _interopRequireDefault(_clickableComponent);
 
-/* Native method references for those with the same name as other `lodash` methods. */
-var nativeMax = Math.max;
+var _component = _dereq_(5);
 
-/**
- * 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);
+var _component2 = _interopRequireDefault(_component);
 
-    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);
-  };
-}
+var _log = _dereq_(85);
 
-module.exports = restParam;
+var _log2 = _interopRequireDefault(_log);
 
-},{}],7:[function(_dereq_,module,exports){
-var debounce = _dereq_('./debounce'),
-    isObject = _dereq_('../lang/isObject');
+var _object = _dereq_(136);
 
-/** Used as the `TypeError` message for "Functions" methods. */
-var FUNC_ERROR_TEXT = 'Expected a function';
+var _object2 = _interopRequireDefault(_object);
 
-/**
- * Creates a throttled function that only invokes `func` at most once per
- * every `wait` milliseconds. The throttled function comes with a `cancel`
- * method to cancel delayed invocations. Provide an options object to indicate
- * that `func` should be invoked on the leading and/or trailing edge of the
- * `wait` timeout. Subsequent calls to the throttled function return the
- * result of the last `func` call.
- *
- * **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
- * on the trailing edge of the timeout only if the the throttled function is
- * invoked more than once during the `wait` timeout.
- *
- * See [David Corbacho's article](http://drupalmotion.com/article/debounce-and-throttle-visual-explanation)
- * for details over the differences between `_.throttle` and `_.debounce`.
- *
- * @static
- * @memberOf _
- * @category Function
- * @param {Function} func The function to throttle.
- * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
- * @param {Object} [options] The options object.
- * @param {boolean} [options.leading=true] Specify invoking on the leading
- *  edge of the timeout.
- * @param {boolean} [options.trailing=true] Specify invoking on the trailing
- *  edge of the timeout.
- * @returns {Function} Returns the new throttled function.
- * @example
- *
- * // avoid excessively updating the position while scrolling
- * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
- *
- * // invoke `renewToken` when the click event is fired, but not more than once every 5 minutes
- * jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
- *   'trailing': false
- * }));
- *
- * // cancel a trailing throttled call
- * jQuery(window).on('popstate', throttled.cancel);
- */
-function throttle(func, wait, options) {
-  var leading = true,
-      trailing = true;
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-  if (typeof func != 'function') {
-    throw new TypeError(FUNC_ERROR_TEXT);
-  }
-  if (options === false) {
-    leading = false;
-  } else if (isObject(options)) {
-    leading = 'leading' in options ? !!options.leading : leading;
-    trailing = 'trailing' in options ? !!options.trailing : trailing;
-  }
-  return debounce(func, wait, { 'leading': leading, 'maxWait': +wait, 'trailing': trailing });
-}
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file button.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-module.exports = throttle;
 
-},{"../lang/isObject":33,"./debounce":5}],8:[function(_dereq_,module,exports){
 /**
- * Copies the values of `source` to `array`.
+ * Base class for all buttons
  *
- * @private
- * @param {Array} source The array to copy values from.
- * @param {Array} [array=[]] The array to copy values to.
- * @returns {Array} Returns `array`.
+ * @param {Object} player  Main Player
+ * @param {Object=} options Object of option names and values
+ * @extends ClickableComponent
+ * @class Button
  */
-function arrayCopy(source, array) {
-  var index = -1,
-      length = source.length;
+var Button = function (_ClickableComponent) {
+  _inherits(Button, _ClickableComponent);
 
-  array || (array = Array(length));
-  while (++index < length) {
-    array[index] = source[index];
+  function Button(player, options) {
+    _classCallCheck(this, Button);
+
+    return _possibleConstructorReturn(this, _ClickableComponent.call(this, player, options));
   }
-  return array;
-}
 
-module.exports = arrayCopy;
+  /**
+   * Create the component's DOM element
+   *
+   * @param {String=} type Element's node type. e.g. 'div'
+   * @param {Object=} props An object of properties that should be set on the element
+   * @param {Object=} attributes An object of attributes that should be set on the element
+   * @return {Element}
+   * @method createEl
+   */
 
-},{}],9:[function(_dereq_,module,exports){
-/**
- * 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;
-}
+  Button.prototype.createEl = function createEl() {
+    var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'button';
+    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
 
-module.exports = arrayEach;
+    props = (0, _object2['default'])({
+      className: this.buildCSSClass()
+    }, props);
 
-},{}],10:[function(_dereq_,module,exports){
-/**
- * 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 = {});
+    if (tag !== 'button') {
+      _log2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.');
 
-  var index = -1,
-      length = props.length;
+      // Add properties for clickable element which is not a native HTML button
+      props = (0, _object2['default'])({
+        tabIndex: 0
+      }, props);
 
-  while (++index < length) {
-    var key = props[index];
-    object[key] = source[key];
-  }
-  return object;
-}
+      // Add ARIA attributes for clickable element which is not a native HTML button
+      attributes = (0, _object2['default'])({
+        role: 'button'
+      }, attributes);
+    }
 
-module.exports = baseCopy;
+    // Add attributes for button element
+    attributes = (0, _object2['default'])({
 
-},{}],11:[function(_dereq_,module,exports){
-var createBaseFor = _dereq_('./createBaseFor');
+      // Necessary since the default button type is "submit"
+      'type': 'button',
 
-/**
- * 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();
+      // let the screen reader user know that the text of the button may change
+      'aria-live': 'polite'
+    }, attributes);
 
-module.exports = baseFor;
+    var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes);
 
-},{"./createBaseFor":18}],12:[function(_dereq_,module,exports){
-var baseFor = _dereq_('./baseFor'),
-    keysIn = _dereq_('../object/keysIn');
+    this.createControlTextEl(el);
 
-/**
- * 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);
-}
+    return el;
+  };
 
-module.exports = baseForIn;
+  /**
+   * Adds a child component inside this button
+   *
+   * @param {String|Component} child The class name or instance of a child to add
+   * @param {Object=} options Options, including options to be passed to children of the child.
+   * @return {Component} The child component (created by this process if a string was used)
+   * @deprecated
+   * @method addChild
+   */
 
-},{"../object/keysIn":39,"./baseFor":11}],13:[function(_dereq_,module,exports){
-var arrayEach = _dereq_('./arrayEach'),
-    baseMergeDeep = _dereq_('./baseMergeDeep'),
-    isArray = _dereq_('../lang/isArray'),
-    isArrayLike = _dereq_('./isArrayLike'),
-    isObject = _dereq_('../lang/isObject'),
-    isObjectLike = _dereq_('./isObjectLike'),
-    isTypedArray = _dereq_('../lang/isTypedArray'),
-    keys = _dereq_('../object/keys');
 
-/**
- * The base implementation of `_.merge` 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 merged values.
- * @param {Array} [stackA=[]] Tracks traversed source objects.
- * @param {Array} [stackB=[]] Associates values with source counterparts.
- * @returns {Object} Returns `object`.
- */
-function baseMerge(object, source, customizer, stackA, stackB) {
-  if (!isObject(object)) {
-    return object;
-  }
-  var isSrcArr = isArrayLike(source) && (isArray(source) || isTypedArray(source)),
-      props = isSrcArr ? undefined : keys(source);
+  Button.prototype.addChild = function addChild(child) {
+    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 
-  arrayEach(props || source, function(srcValue, key) {
-    if (props) {
-      key = srcValue;
-      srcValue = source[key];
-    }
-    if (isObjectLike(srcValue)) {
-      stackA || (stackA = []);
-      stackB || (stackB = []);
-      baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB);
-    }
-    else {
-      var value = object[key],
-          result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
-          isCommon = result === undefined;
+    var className = this.constructor.name;
 
-      if (isCommon) {
-        result = srcValue;
-      }
-      if ((result !== undefined || (isSrcArr && !(key in object))) &&
-          (isCommon || (result === result ? (result !== value) : (value === value)))) {
-        object[key] = result;
-      }
-    }
-  });
-  return object;
-}
+    _log2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.');
 
-module.exports = baseMerge;
+    // Avoid the error message generated by ClickableComponent's addChild method
+    return _component2['default'].prototype.addChild.call(this, child, options);
+  };
 
-},{"../lang/isArray":30,"../lang/isObject":33,"../lang/isTypedArray":36,"../object/keys":38,"./arrayEach":9,"./baseMergeDeep":14,"./isArrayLike":21,"./isObjectLike":26}],14:[function(_dereq_,module,exports){
-var arrayCopy = _dereq_('./arrayCopy'),
-    isArguments = _dereq_('../lang/isArguments'),
-    isArray = _dereq_('../lang/isArray'),
-    isArrayLike = _dereq_('./isArrayLike'),
-    isPlainObject = _dereq_('../lang/isPlainObject'),
-    isTypedArray = _dereq_('../lang/isTypedArray'),
-    toPlainObject = _dereq_('../lang/toPlainObject');
+  /**
+   * Handle KeyPress (document level) - Extend with specific functionality for button
+   *
+   * @method handleKeyPress
+   */
 
-/**
- * A specialized version of `baseMerge` for arrays and objects which performs
- * deep merges and tracks traversed objects enabling objects with circular
- * references to be merged.
- *
- * @private
- * @param {Object} object The destination object.
- * @param {Object} source The source object.
- * @param {string} key The key of the value to merge.
- * @param {Function} mergeFunc The function to merge values.
- * @param {Function} [customizer] The function to customize merged values.
- * @param {Array} [stackA=[]] Tracks traversed source objects.
- * @param {Array} [stackB=[]] Associates values with source counterparts.
- * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
- */
-function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) {
-  var length = stackA.length,
-      srcValue = source[key];
 
-  while (length--) {
-    if (stackA[length] == srcValue) {
-      object[key] = stackB[length];
+  Button.prototype.handleKeyPress = function handleKeyPress(event) {
+
+    // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button.
+    if (event.which === 32 || event.which === 13) {
       return;
     }
-  }
-  var value = object[key],
-      result = customizer ? customizer(value, srcValue, key, object, source) : undefined,
-      isCommon = result === undefined;
 
-  if (isCommon) {
-    result = srcValue;
-    if (isArrayLike(srcValue) && (isArray(srcValue) || isTypedArray(srcValue))) {
-      result = isArray(value)
-        ? value
-        : (isArrayLike(value) ? arrayCopy(value) : []);
-    }
-    else if (isPlainObject(srcValue) || isArguments(srcValue)) {
-      result = isArguments(value)
-        ? toPlainObject(value)
-        : (isPlainObject(value) ? value : {});
-    }
-    else {
-      isCommon = false;
-    }
-  }
-  // Add the source value to the stack of traversed objects and associate
-  // it with its merged value.
-  stackA.push(srcValue);
-  stackB.push(result);
+    // Pass keypress handling up for unsupported keys
+    _ClickableComponent.prototype.handleKeyPress.call(this, event);
+  };
 
-  if (isCommon) {
-    // Recursively merge objects and arrays (susceptible to call stack limits).
-    object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB);
-  } else if (result === result ? (result !== value) : (value === value)) {
-    object[key] = result;
-  }
-}
+  return Button;
+}(_clickableComponent2['default']);
 
-module.exports = baseMergeDeep;
+_component2['default'].registerComponent('Button', Button);
+exports['default'] = Button;
 
-},{"../lang/isArguments":29,"../lang/isArray":30,"../lang/isPlainObject":34,"../lang/isTypedArray":36,"../lang/toPlainObject":37,"./arrayCopy":8,"./isArrayLike":21}],15:[function(_dereq_,module,exports){
-var toObject = _dereq_('./toObject');
+},{"136":136,"3":3,"5":5,"85":85}],3:[function(_dereq_,module,exports){
+'use strict';
 
-/**
- * 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 : toObject(object)[key];
-  };
-}
+exports.__esModule = true;
 
-module.exports = baseProperty;
+var _component = _dereq_(5);
 
-},{"./toObject":28}],16:[function(_dereq_,module,exports){
-var identity = _dereq_('../utility/identity');
+var _component2 = _interopRequireDefault(_component);
 
-/**
- * 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);
-  };
-}
+var _dom = _dereq_(80);
 
-module.exports = bindCallback;
+var Dom = _interopRequireWildcard(_dom);
 
-},{"../utility/identity":42}],17:[function(_dereq_,module,exports){
-var bindCallback = _dereq_('./bindCallback'),
-    isIterateeCall = _dereq_('./isIterateeCall'),
-    restParam = _dereq_('../function/restParam');
+var _events = _dereq_(81);
 
-/**
- * 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;
+var Events = _interopRequireWildcard(_events);
 
-    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;
-  });
-}
+var _fn = _dereq_(82);
 
-module.exports = createAssigner;
+var Fn = _interopRequireWildcard(_fn);
 
-},{"../function/restParam":6,"./bindCallback":16,"./isIterateeCall":24}],18:[function(_dereq_,module,exports){
-var toObject = _dereq_('./toObject');
+var _log = _dereq_(85);
 
-/**
- * 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;
+var _log2 = _interopRequireDefault(_log);
 
-    while ((fromRight ? index-- : ++index < length)) {
-      var key = props[index];
-      if (iteratee(iterable[key], key, iterable) === false) {
-        break;
-      }
-    }
-    return object;
-  };
-}
+var _document = _dereq_(92);
 
-module.exports = createBaseFor;
+var _document2 = _interopRequireDefault(_document);
 
-},{"./toObject":28}],19:[function(_dereq_,module,exports){
-var baseProperty = _dereq_('./baseProperty');
+var _object = _dereq_(136);
 
-/**
- * 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');
+var _object2 = _interopRequireDefault(_object);
 
-module.exports = getLength;
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-},{"./baseProperty":15}],20:[function(_dereq_,module,exports){
-var isNative = _dereq_('../lang/isNative');
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-/**
- * 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;
-}
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-module.exports = getNative;
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file button.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-},{"../lang/isNative":32}],21:[function(_dereq_,module,exports){
-var getLength = _dereq_('./getLength'),
-    isLength = _dereq_('./isLength');
 
 /**
- * Checks if `value` is array-like.
+ * Clickable Component which is clickable or keyboard actionable, but is not a native HTML button
  *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
+ * @param {Object} player  Main Player
+ * @param {Object=} options Object of option names and values
+ * @extends Component
+ * @class ClickableComponent
  */
-function isArrayLike(value) {
-  return value != null && isLength(getLength(value));
-}
+var ClickableComponent = function (_Component) {
+  _inherits(ClickableComponent, _Component);
 
-module.exports = isArrayLike;
+  function ClickableComponent(player, options) {
+    _classCallCheck(this, ClickableComponent);
 
-},{"./getLength":19,"./isLength":25}],22:[function(_dereq_,module,exports){
-/**
- * Checks if `value` is a host object in IE < 9.
- *
- * @private
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is a host object, else `false`.
- */
-var isHostObject = (function() {
-  try {
-    Object({ 'toString': 0 } + '');
-  } catch(e) {
-    return function() { return false; };
+    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
+
+    _this.emitTapEvents();
+
+    _this.on('tap', _this.handleClick);
+    _this.on('click', _this.handleClick);
+    _this.on('focus', _this.handleFocus);
+    _this.on('blur', _this.handleBlur);
+    return _this;
   }
-  return function(value) {
-    // IE < 9 presents many host objects as `Object` objects that can coerce
-    // to strings despite having improperly defined `toString` methods.
-    return typeof value.toString != 'function' && typeof (value + '') == 'string';
-  };
-}());
 
-module.exports = isHostObject;
+  /**
+   * Create the component's DOM element
+   *
+   * @param {String=} type Element's node type. e.g. 'div'
+   * @param {Object=} props An object of properties that should be set on the element
+   * @param {Object=} attributes An object of attributes that should be set on the element
+   * @return {Element}
+   * @method createEl
+   */
 
-},{}],23:[function(_dereq_,module,exports){
-/** 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;
+  ClickableComponent.prototype.createEl = function createEl() {
+    var tag = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div';
+    var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+    var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
 
-/**
- * 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;
-}
+    props = (0, _object2['default'])({
+      className: this.buildCSSClass(),
+      tabIndex: 0
+    }, props);
 
-module.exports = isIndex;
+    if (tag === 'button') {
+      _log2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.');
+    }
 
-},{}],24:[function(_dereq_,module,exports){
-var isArrayLike = _dereq_('./isArrayLike'),
-    isIndex = _dereq_('./isIndex'),
-    isObject = _dereq_('../lang/isObject');
+    // Add ARIA attributes for clickable element which is not a native HTML button
+    attributes = (0, _object2['default'])({
+      'role': 'button',
 
-/**
- * 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;
-}
+      // let the screen reader user know that the text of the element may change
+      'aria-live': 'polite'
+    }, attributes);
 
-module.exports = isIterateeCall;
+    var el = _Component.prototype.createEl.call(this, tag, props, attributes);
 
-},{"../lang/isObject":33,"./isArrayLike":21,"./isIndex":23}],25:[function(_dereq_,module,exports){
-/**
- * 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;
+    this.createControlTextEl(el);
 
-/**
- * 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;
-}
+    return el;
+  };
 
-module.exports = isLength;
+  /**
+   * create control text
+   *
+   * @param {Element} el Parent element for the control text
+   * @return {Element}
+   * @method controlText
+   */
 
-},{}],26:[function(_dereq_,module,exports){
-/**
- * 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';
-}
 
-module.exports = isObjectLike;
+  ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) {
+    this.controlTextEl_ = Dom.createEl('span', {
+      className: 'vjs-control-text'
+    });
 
-},{}],27:[function(_dereq_,module,exports){
-var isArguments = _dereq_('../lang/isArguments'),
-    isArray = _dereq_('../lang/isArray'),
-    isIndex = _dereq_('./isIndex'),
-    isLength = _dereq_('./isLength'),
-    isString = _dereq_('../lang/isString'),
-    keysIn = _dereq_('../object/keysIn');
+    if (el) {
+      el.appendChild(this.controlTextEl_);
+    }
 
-/** Used for native method references. */
-var objectProto = Object.prototype;
+    this.controlText(this.controlText_, el);
 
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
+    return this.controlTextEl_;
+  };
 
-/**
- * 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;
+  /**
+   * Controls text - both request and localize
+   *
+   * @param {String}  text Text for element
+   * @param {Element=} el Element to set the title on
+   * @return {String}
+   * @method controlText
+   */
 
-  var allowIndexes = !!length && isLength(length) &&
-    (isArray(object) || isArguments(object) || isString(object));
 
-  var index = -1,
-      result = [];
+  ClickableComponent.prototype.controlText = function controlText(text) {
+    var el = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.el();
 
-  while (++index < propsLength) {
-    var key = props[index];
-    if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) {
-      result.push(key);
+    if (!text) {
+      return this.controlText_ || 'Need Text';
     }
-  }
-  return result;
-}
 
-module.exports = shimKeys;
+    var localizedText = this.localize(text);
 
-},{"../lang/isArguments":29,"../lang/isArray":30,"../lang/isString":35,"../object/keysIn":39,"./isIndex":23,"./isLength":25}],28:[function(_dereq_,module,exports){
-var isObject = _dereq_('../lang/isObject'),
-    isString = _dereq_('../lang/isString'),
-    support = _dereq_('../support');
+    this.controlText_ = text;
+    this.controlTextEl_.innerHTML = localizedText;
+    el.setAttribute('title', localizedText);
 
-/**
- * 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) {
-  if (support.unindexedChars && isString(value)) {
-    var index = -1,
-        length = value.length,
-        result = Object(value);
+    return this;
+  };
 
-    while (++index < length) {
-      result[index] = value.charAt(index);
-    }
-    return result;
-  }
-  return isObject(value) ? value : Object(value);
-}
+  /**
+   * Allows sub components to stack CSS class names
+   *
+   * @return {String}
+   * @method buildCSSClass
+   */
 
-module.exports = toObject;
 
-},{"../lang/isObject":33,"../lang/isString":35,"../support":41}],29:[function(_dereq_,module,exports){
-var isArrayLike = _dereq_('../internal/isArrayLike'),
-    isObjectLike = _dereq_('../internal/isObjectLike');
+  ClickableComponent.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this);
+  };
 
-/** Used for native method references. */
-var objectProto = Object.prototype;
+  /**
+   * Adds a child component inside this clickable-component
+   *
+   * @param {String|Component} child The class name or instance of a child to add
+   * @param {Object=} options Options, including options to be passed to children of the child.
+   * @return {Component} The child component (created by this process if a string was used)
+   * @method addChild
+   */
 
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
 
-/** Native method references. */
-var propertyIsEnumerable = objectProto.propertyIsEnumerable;
+  ClickableComponent.prototype.addChild = function addChild(child) {
+    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 
-/**
- * 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');
-}
+    // TODO: Fix adding an actionable child to a ClickableComponent; currently
+    // it will cause issues with assistive technology (e.g. screen readers)
+    // which support ARIA, since an element with role="button" cannot have
+    // actionable child elements.
 
-module.exports = isArguments;
+    // let className = this.constructor.name;
+    // log.warn(`Adding a child to a ClickableComponent (${className}) can cause issues with assistive technology which supports ARIA, since an element with role="button" cannot have actionable child elements.`);
 
-},{"../internal/isArrayLike":21,"../internal/isObjectLike":26}],30:[function(_dereq_,module,exports){
-var getNative = _dereq_('../internal/getNative'),
-    isLength = _dereq_('../internal/isLength'),
-    isObjectLike = _dereq_('../internal/isObjectLike');
+    return _Component.prototype.addChild.call(this, child, options);
+  };
 
-/** `Object#toString` result references. */
-var arrayTag = '[object Array]';
+  /**
+   * Enable the component element
+   *
+   * @return {Component}
+   * @method enable
+   */
 
-/** 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;
+  ClickableComponent.prototype.enable = function enable() {
+    this.removeClass('vjs-disabled');
+    this.el_.setAttribute('aria-disabled', 'false');
+    return this;
+  };
 
-/* 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;
-};
+  /**
+   * Disable the component element
+   *
+   * @return {Component}
+   * @method disable
+   */
 
-module.exports = isArray;
 
-},{"../internal/getNative":20,"../internal/isLength":25,"../internal/isObjectLike":26}],31:[function(_dereq_,module,exports){
-var isObject = _dereq_('./isObject');
+  ClickableComponent.prototype.disable = function disable() {
+    this.addClass('vjs-disabled');
+    this.el_.setAttribute('aria-disabled', 'true');
+    return this;
+  };
 
-/** `Object#toString` result references. */
-var funcTag = '[object Function]';
+  /**
+   * Handle Click - Override with specific functionality for component
+   *
+   * @method handleClick
+   */
 
-/** 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;
+  ClickableComponent.prototype.handleClick = function handleClick() {};
 
-/**
- * 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;
-}
+  /**
+   * Handle Focus - Add keyboard functionality to element
+   *
+   * @method handleFocus
+   */
 
-module.exports = isFunction;
 
-},{"./isObject":33}],32:[function(_dereq_,module,exports){
-var isFunction = _dereq_('./isFunction'),
-    isHostObject = _dereq_('../internal/isHostObject'),
-    isObjectLike = _dereq_('../internal/isObjectLike');
+  ClickableComponent.prototype.handleFocus = function handleFocus() {
+    Events.on(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
+  };
 
-/** Used to detect host constructors (Safari > 5). */
-var reIsHostCtor = /^\[object .+?Constructor\]$/;
+  /**
+   * Handle KeyPress (document level) - Trigger click when Space or Enter key is pressed
+   *
+   * @method handleKeyPress
+   */
 
-/** Used for native method references. */
-var objectProto = Object.prototype;
 
-/** Used to resolve the decompiled source of functions. */
-var fnToString = Function.prototype.toString;
+  ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) {
 
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
+    // Support Space (32) or Enter (13) key operation to fire a click event
+    if (event.which === 32 || event.which === 13) {
+      event.preventDefault();
+      this.handleClick(event);
+    } else if (_Component.prototype.handleKeyPress) {
 
-/** Used to detect if a method is native. */
-var reIsNative = RegExp('^' +
-  fnToString.call(hasOwnProperty).replace(/[\\^$.*+?()[\]{}|]/g, '\\$&')
-  .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
-);
+      // Pass keypress handling up for unsupported keys
+      _Component.prototype.handleKeyPress.call(this, event);
+    }
+  };
 
-/**
- * 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) && (isHostObject(value) ? reIsNative : reIsHostCtor).test(value);
-}
+  /**
+   * Handle Blur - Remove keyboard triggers
+   *
+   * @method handleBlur
+   */
 
-module.exports = isNative;
 
-},{"../internal/isHostObject":22,"../internal/isObjectLike":26,"./isFunction":31}],33:[function(_dereq_,module,exports){
-/**
- * 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');
-}
+  ClickableComponent.prototype.handleBlur = function handleBlur() {
+    Events.off(_document2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
+  };
 
-module.exports = isObject;
+  return ClickableComponent;
+}(_component2['default']);
 
-},{}],34:[function(_dereq_,module,exports){
-var baseForIn = _dereq_('../internal/baseForIn'),
-    isArguments = _dereq_('./isArguments'),
-    isHostObject = _dereq_('../internal/isHostObject'),
-    isObjectLike = _dereq_('../internal/isObjectLike'),
-    support = _dereq_('../support');
+_component2['default'].registerComponent('ClickableComponent', ClickableComponent);
+exports['default'] = ClickableComponent;
 
-/** `Object#toString` result references. */
-var objectTag = '[object Object]';
+},{"136":136,"5":5,"80":80,"81":81,"82":82,"85":85,"92":92}],4:[function(_dereq_,module,exports){
+'use strict';
 
-/** Used for native method references. */
-var objectProto = Object.prototype;
+exports.__esModule = true;
 
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
+var _button = _dereq_(2);
 
-/**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+var _button2 = _interopRequireDefault(_button);
 
-/**
- * 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;
+var _component = _dereq_(5);
 
-  // Exit early for non `Object` objects.
-  if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value) && !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;
-  if (support.ownLast) {
-    baseForIn(value, function(subValue, key, object) {
-      result = hasOwnProperty.call(object, key);
-      return false;
-    });
-    return result !== false;
-  }
-  // 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);
-}
+var _component2 = _interopRequireDefault(_component);
 
-module.exports = isPlainObject;
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-},{"../internal/baseForIn":12,"../internal/isHostObject":22,"../internal/isObjectLike":26,"../support":41,"./isArguments":29}],35:[function(_dereq_,module,exports){
-var isObjectLike = _dereq_('../internal/isObjectLike');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-/** `Object#toString` result references. */
-var stringTag = '[object String]';
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-/** Used for native method references. */
-var objectProto = Object.prototype;
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
 
 /**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
+ * The `CloseButton` component is a button which fires a "close" event
+ * when it is activated.
+ *
+ * @extends Button
+ * @class CloseButton
  */
-var objToString = objectProto.toString;
+var CloseButton = function (_Button) {
+  _inherits(CloseButton, _Button);
 
-/**
- * Checks if `value` is classified as a `String` primitive or object.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to check.
- * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`.
- * @example
- *
- * _.isString('abc');
- * // => true
- *
- * _.isString(1);
- * // => false
- */
-function isString(value) {
-  return typeof value == 'string' || (isObjectLike(value) && objToString.call(value) == stringTag);
-}
+  function CloseButton(player, options) {
+    _classCallCheck(this, CloseButton);
 
-module.exports = isString;
+    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
 
-},{"../internal/isObjectLike":26}],36:[function(_dereq_,module,exports){
-var isLength = _dereq_('../internal/isLength'),
-    isObjectLike = _dereq_('../internal/isObjectLike');
+    _this.controlText(options && options.controlText || _this.localize('Close'));
+    return _this;
+  }
 
-/** `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]';
+  CloseButton.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this);
+  };
 
-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]';
+  CloseButton.prototype.handleClick = function handleClick() {
+    this.trigger({ type: 'close', bubbles: false });
+  };
 
-/** 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;
+  return CloseButton;
+}(_button2['default']);
 
-/** Used for native method references. */
-var objectProto = Object.prototype;
+_component2['default'].registerComponent('CloseButton', CloseButton);
+exports['default'] = CloseButton;
 
-/**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+},{"2":2,"5":5}],5:[function(_dereq_,module,exports){
+'use strict';
 
-/**
- * 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)];
-}
+exports.__esModule = true;
 
-module.exports = isTypedArray;
+var _window = _dereq_(93);
 
-},{"../internal/isLength":25,"../internal/isObjectLike":26}],37:[function(_dereq_,module,exports){
-var baseCopy = _dereq_('../internal/baseCopy'),
-    keysIn = _dereq_('../object/keysIn');
+var _window2 = _interopRequireDefault(_window);
 
-/**
- * Converts `value` to a plain object flattening inherited enumerable
- * properties of `value` to own properties of the plain object.
- *
- * @static
- * @memberOf _
- * @category Lang
- * @param {*} value The value to convert.
- * @returns {Object} Returns the converted plain object.
- * @example
- *
- * function Foo() {
- *   this.b = 2;
- * }
- *
- * Foo.prototype.c = 3;
- *
- * _.assign({ 'a': 1 }, new Foo);
- * // => { 'a': 1, 'b': 2 }
- *
- * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
- * // => { 'a': 1, 'b': 2, 'c': 3 }
- */
-function toPlainObject(value) {
-  return baseCopy(value, keysIn(value));
-}
+var _dom = _dereq_(80);
 
-module.exports = toPlainObject;
+var Dom = _interopRequireWildcard(_dom);
 
-},{"../internal/baseCopy":10,"../object/keysIn":39}],38:[function(_dereq_,module,exports){
-var getNative = _dereq_('../internal/getNative'),
-    isArrayLike = _dereq_('../internal/isArrayLike'),
-    isObject = _dereq_('../lang/isObject'),
-    shimKeys = _dereq_('../internal/shimKeys'),
-    support = _dereq_('../support');
+var _fn = _dereq_(82);
 
-/* Native method references for those with the same name as other `lodash` methods. */
-var nativeKeys = getNative(Object, 'keys');
+var Fn = _interopRequireWildcard(_fn);
 
-/**
- * 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' ? support.enumPrototypes : isArrayLike(object))) {
-    return shimKeys(object);
-  }
-  return isObject(object) ? nativeKeys(object) : [];
-};
+var _guid = _dereq_(84);
 
-module.exports = keys;
+var Guid = _interopRequireWildcard(_guid);
 
-},{"../internal/getNative":20,"../internal/isArrayLike":21,"../internal/shimKeys":27,"../lang/isObject":33,"../support":41}],39:[function(_dereq_,module,exports){
-var arrayEach = _dereq_('../internal/arrayEach'),
-    isArguments = _dereq_('../lang/isArguments'),
-    isArray = _dereq_('../lang/isArray'),
-    isFunction = _dereq_('../lang/isFunction'),
-    isIndex = _dereq_('../internal/isIndex'),
-    isLength = _dereq_('../internal/isLength'),
-    isObject = _dereq_('../lang/isObject'),
-    isString = _dereq_('../lang/isString'),
-    support = _dereq_('../support');
+var _events = _dereq_(81);
 
-/** `Object#toString` result references. */
-var arrayTag = '[object Array]',
-    boolTag = '[object Boolean]',
-    dateTag = '[object Date]',
-    errorTag = '[object Error]',
-    funcTag = '[object Function]',
-    numberTag = '[object Number]',
-    objectTag = '[object Object]',
-    regexpTag = '[object RegExp]',
-    stringTag = '[object String]';
+var Events = _interopRequireWildcard(_events);
 
-/** Used to fix the JScript `[[DontEnum]]` bug. */
-var shadowProps = [
-  'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
-  'toLocaleString', 'toString', 'valueOf'
-];
+var _log = _dereq_(85);
 
-/** Used for native method references. */
-var errorProto = Error.prototype,
-    objectProto = Object.prototype,
-    stringProto = String.prototype;
+var _log2 = _interopRequireDefault(_log);
 
-/** Used to check objects for own properties. */
-var hasOwnProperty = objectProto.hasOwnProperty;
+var _toTitleCase = _dereq_(89);
 
-/**
- * Used to resolve the [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
- * of values.
- */
-var objToString = objectProto.toString;
+var _toTitleCase2 = _interopRequireDefault(_toTitleCase);
 
-/** Used to avoid iterating over non-enumerable properties in IE < 9. */
-var nonEnumProps = {};
-nonEnumProps[arrayTag] = nonEnumProps[dateTag] = nonEnumProps[numberTag] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
-nonEnumProps[boolTag] = nonEnumProps[stringTag] = { 'constructor': true, 'toString': true, 'valueOf': true };
-nonEnumProps[errorTag] = nonEnumProps[funcTag] = nonEnumProps[regexpTag] = { 'constructor': true, 'toString': true };
-nonEnumProps[objectTag] = { 'constructor': true };
+var _mergeOptions = _dereq_(86);
 
-arrayEach(shadowProps, function(key) {
-  for (var tag in nonEnumProps) {
-    if (hasOwnProperty.call(nonEnumProps, tag)) {
-      var props = nonEnumProps[tag];
-      props[key] = hasOwnProperty.call(props, key);
-    }
-  }
-});
+var _mergeOptions2 = _interopRequireDefault(_mergeOptions);
 
-/**
- * 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;
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-  length = (length && isLength(length) &&
-    (isArray(object) || isArguments(object) || isString(object)) && length) || 0;
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-  var Ctor = object.constructor,
-      index = -1,
-      proto = (isFunction(Ctor) && Ctor.prototype) || objectProto,
-      isProto = proto === object,
-      result = Array(length),
-      skipIndexes = length > 0,
-      skipErrorProps = support.enumErrorProps && (object === errorProto || object instanceof Error),
-      skipProto = support.enumPrototypes && isFunction(object);
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /**
+                                                                                                                                                           * @file component.js
+                                                                                                                                                           *
+                                                                                                                                                           * Player Component - Base class for all UI objects
+                                                                                                                                                           */
 
-  while (++index < length) {
-    result[index] = (index + '');
-  }
-  // lodash skips the `constructor` property when it infers it's iterating
-  // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]`
-  // attribute of an existing property and the `constructor` property of a
-  // prototype defaults to non-enumerable.
-  for (var key in object) {
-    if (!(skipProto && key == 'prototype') &&
-        !(skipErrorProps && (key == 'message' || key == 'name')) &&
-        !(skipIndexes && isIndex(key, length)) &&
-        !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
-      result.push(key);
-    }
-  }
-  if (support.nonEnumShadows && object !== objectProto) {
-    var tag = object === stringProto ? stringTag : (object === errorProto ? errorTag : objToString.call(object)),
-        nonEnums = nonEnumProps[tag] || nonEnumProps[objectTag];
-
-    if (tag == objectTag) {
-      proto = objectProto;
-    }
-    length = shadowProps.length;
-    while (length--) {
-      key = shadowProps[length];
-      var nonEnum = nonEnums[key];
-      if (!(isProto && nonEnum) &&
-          (nonEnum ? hasOwnProperty.call(object, key) : object[key] !== proto[key])) {
-        result.push(key);
-      }
-    }
-  }
-  return result;
-}
-
-module.exports = keysIn;
-
-},{"../internal/arrayEach":9,"../internal/isIndex":23,"../internal/isLength":25,"../lang/isArguments":29,"../lang/isArray":30,"../lang/isFunction":31,"../lang/isObject":33,"../lang/isString":35,"../support":41}],40:[function(_dereq_,module,exports){
-var baseMerge = _dereq_('../internal/baseMerge'),
-    createAssigner = _dereq_('../internal/createAssigner');
 
 /**
- * Recursively merges own enumerable properties of the source object(s), that
- * don't resolve to `undefined` into the destination object. Subsequent sources
- * overwrite property assignments of previous sources. If `customizer` is
- * provided it's invoked to produce the merged values of the destination and
- * source properties. If `customizer` returns `undefined` merging is handled
- * by the method instead. The `customizer` is bound to `thisArg` and invoked
- * with five arguments: (objectValue, sourceValue, key, object, source).
- *
- * @static
- * @memberOf _
- * @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
- *
- * var users = {
- *   'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
- * };
- *
- * var ages = {
- *   'data': [{ 'age': 36 }, { 'age': 40 }]
- * };
- *
- * _.merge(users, ages);
- * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
- *
- * // using a customizer callback
- * var object = {
- *   'fruits': ['apple'],
- *   'vegetables': ['beet']
- * };
- *
- * var other = {
- *   'fruits': ['banana'],
- *   'vegetables': ['carrot']
- * };
+ * Base UI Component class
+ * Components are embeddable UI objects that are represented by both a
+ * javascript object and an element in the DOM. They can be children of other
+ * components, and can have many children themselves.
+ * ```js
+ *     // adding a button to the player
+ *     var button = player.addChild('button');
+ *     button.el(); // -> button element
+ * ```
+ * ```html
+ *     <div class="video-js">
+ *       <div class="vjs-button">Button</div>
+ *     </div>
+ * ```
+ * Components are also event targets.
+ * ```js
+ *     button.on('click', function() {
+ *       console.log('Button Clicked!');
+ *     });
+ *     button.trigger('customevent');
+ * ```
  *
- * _.merge(object, other, function(a, b) {
- *   if (_.isArray(a)) {
- *     return a.concat(b);
- *   }
- * });
- * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
+ * @param {Object} player  Main Player
+ * @param {Object=} options Object of option names and values
+ * @param {Function=} ready    Ready callback function
+ * @class Component
  */
-var merge = createAssigner(baseMerge);
+var Component = function () {
+  function Component(player, options, ready) {
+    _classCallCheck(this, Component);
 
-module.exports = merge;
+    // The component might be the player itself and we can't pass `this` to super
+    if (!player && this.play) {
+      this.player_ = player = this; // eslint-disable-line
+    } else {
+      this.player_ = player;
+    }
 
-},{"../internal/baseMerge":13,"../internal/createAssigner":17}],41:[function(_dereq_,module,exports){
-/** Used for native method references. */
-var arrayProto = Array.prototype,
-    errorProto = Error.prototype,
-    objectProto = Object.prototype;
+    // Make a copy of prototype.options_ to protect against overriding defaults
+    this.options_ = (0, _mergeOptions2['default'])({}, this.options_);
 
-/** Native method references. */
-var propertyIsEnumerable = objectProto.propertyIsEnumerable,
-    splice = arrayProto.splice;
+    // Updated options with supplied options
+    options = this.options_ = (0, _mergeOptions2['default'])(this.options_, options);
 
-/**
- * An object environment feature flags.
- *
- * @static
- * @memberOf _
- * @type Object
- */
-var support = {};
+    // Get ID from options or options element if one is supplied
+    this.id_ = options.id || options.el && options.el.id;
 
-(function(x) {
-  var Ctor = function() { this.x = x; },
-      object = { '0': x, 'length': x },
-      props = [];
+    // If there was no ID from the options, generate one
+    if (!this.id_) {
+      // Don't require the player ID function in the case of mock players
+      var id = player && player.id && player.id() || 'no_player';
 
-  Ctor.prototype = { 'valueOf': x, 'y': x };
-  for (var key in new Ctor) { props.push(key); }
+      this.id_ = id + '_component_' + Guid.newGUID();
+    }
 
-  /**
-   * Detect if `name` or `message` properties of `Error.prototype` are
-   * enumerable by default (IE < 9, Safari < 5.1).
-   *
-   * @memberOf _.support
-   * @type boolean
-   */
-  support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') ||
-    propertyIsEnumerable.call(errorProto, 'name');
+    this.name_ = options.name || null;
 
-  /**
-   * Detect if `prototype` properties are enumerable by default.
-   *
-   * Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
-   * (if the prototype or a property on the prototype has been set)
-   * incorrectly set the `[[Enumerable]]` value of a function's `prototype`
-   * property to `true`.
-   *
-   * @memberOf _.support
-   * @type boolean
-   */
-  support.enumPrototypes = propertyIsEnumerable.call(Ctor, 'prototype');
+    // Create element if one wasn't provided in options
+    if (options.el) {
+      this.el_ = options.el;
+    } else if (options.createEl !== false) {
+      this.el_ = this.createEl();
+    }
 
-  /**
-   * Detect if properties shadowing those on `Object.prototype` are non-enumerable.
-   *
-   * In IE < 9 an object's own properties, shadowing non-enumerable ones,
-   * are made non-enumerable as well (a.k.a the JScript `[[DontEnum]]` bug).
-   *
-   * @memberOf _.support
-   * @type boolean
-   */
-  support.nonEnumShadows = !/valueOf/.test(props);
+    this.children_ = [];
+    this.childIndex_ = {};
+    this.childNameIndex_ = {};
 
-  /**
-   * Detect if own properties are iterated after inherited properties (IE < 9).
-   *
-   * @memberOf _.support
-   * @type boolean
-   */
-  support.ownLast = props[0] != 'x';
+    // Add any child components in options
+    if (options.initChildren !== false) {
+      this.initChildren();
+    }
 
-  /**
-   * Detect if `Array#shift` and `Array#splice` augment array-like objects
-   * correctly.
-   *
-   * Firefox < 10, compatibility modes of IE 8, and IE < 9 have buggy Array
-   * `shift()` and `splice()` functions that fail to remove the last element,
-   * `value[0]`, of array-like objects even though the "length" property is
-   * set to `0`. The `shift()` method is buggy in compatibility modes of IE 8,
-   * while `splice()` is buggy regardless of mode in IE < 9.
-   *
-   * @memberOf _.support
-   * @type boolean
-   */
-  support.spliceObjects = (splice.call(object, 0, 1), !object[0]);
+    this.ready(ready);
+    // Don't want to trigger ready here or it will before init is actually
+    // finished for all children that run this constructor
+
+    if (options.reportTouchActivity !== false) {
+      this.enableTouchActivity();
+    }
+  }
 
   /**
-   * Detect lack of support for accessing string characters by index.
-   *
-   * IE < 8 can't access characters by index. IE 8 can only access characters
-   * by index on string literals, not string objects.
+   * Dispose of the component and all child components
    *
-   * @memberOf _.support
-   * @type boolean
+   * @method dispose
    */
-  support.unindexedChars = ('x'[0] + Object('x')[0]) != 'xx';
-}(1, 0));
 
-module.exports = support;
 
-},{}],42:[function(_dereq_,module,exports){
-/**
- * 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;
-}
+  Component.prototype.dispose = function dispose() {
+    this.trigger({ type: 'dispose', bubbles: false });
 
-module.exports = identity;
+    // Dispose all children.
+    if (this.children_) {
+      for (var i = this.children_.length - 1; i >= 0; i--) {
+        if (this.children_[i].dispose) {
+          this.children_[i].dispose();
+        }
+      }
+    }
 
-},{}],43:[function(_dereq_,module,exports){
-'use strict';
+    // Delete child references
+    this.children_ = null;
+    this.childIndex_ = null;
+    this.childNameIndex_ = null;
 
-var keys = _dereq_('object-keys');
+    // Remove all event listeners.
+    this.off();
 
-module.exports = function hasSymbols() {
-       if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; }
-       if (typeof Symbol.iterator === 'symbol') { return true; }
+    // Remove element from DOM
+    if (this.el_.parentNode) {
+      this.el_.parentNode.removeChild(this.el_);
+    }
 
-       var obj = {};
-       var sym = Symbol('test');
-       if (typeof sym === 'string') { return false; }
+    Dom.removeElData(this.el_);
+    this.el_ = null;
+  };
 
-       // temp disabled per https://github.com/ljharb/object.assign/issues/17
-       // if (sym instanceof Symbol) { return false; }
-       // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4
-       // if (!(Object(sym) instanceof Symbol)) { return false; }
+  /**
+   * Return the component's player
+   *
+   * @return {Player}
+   * @method player
+   */
 
-       var symVal = 42;
-       obj[sym] = symVal;
-       for (sym in obj) { return false; }
-       if (keys(obj).length !== 0) { return false; }
-       if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; }
 
-       if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; }
+  Component.prototype.player = function player() {
+    return this.player_;
+  };
 
-       var syms = Object.getOwnPropertySymbols(obj);
-       if (syms.length !== 1 || syms[0] !== sym) { return false; }
+  /**
+   * Deep merge of options objects
+   * Whenever a property is an object on both options objects
+   * the two properties will be merged using mergeOptions.
+   *
+   * ```js
+   *     Parent.prototype.options_ = {
+   *       optionSet: {
+   *         'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
+   *         'childTwo': {},
+   *         'childThree': {}
+   *       }
+   *     }
+   *     newOptions = {
+   *       optionSet: {
+   *         'childOne': { 'foo': 'baz', 'abc': '123' }
+   *         'childTwo': null,
+   *         'childFour': {}
+   *       }
+   *     }
+   *
+   *     this.options(newOptions);
+   * ```
+   * RESULT
+   * ```js
+   *     {
+   *       optionSet: {
+   *         'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' },
+   *         'childTwo': null, // Disabled. Won't be initialized.
+   *         'childThree': {},
+   *         'childFour': {}
+   *       }
+   *     }
+   * ```
+   *
+   * @param  {Object} obj Object of new option values
+   * @return {Object}     A NEW object of this.options_ and obj merged
+   * @method options
+   */
 
-       if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; }
 
-       if (typeof Object.getOwnPropertyDescriptor === 'function') {
-               var descriptor = Object.getOwnPropertyDescriptor(obj, sym);
-               if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; }
-       }
+  Component.prototype.options = function options(obj) {
+    _log2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
 
-       return true;
-};
+    if (!obj) {
+      return this.options_;
+    }
 
-},{"object-keys":50}],44:[function(_dereq_,module,exports){
-'use strict';
+    this.options_ = (0, _mergeOptions2['default'])(this.options_, obj);
+    return this.options_;
+  };
 
-// modified from https://github.com/es-shims/es6-shim
-var keys = _dereq_('object-keys');
-var bind = _dereq_('function-bind');
-var canBeObject = function (obj) {
-       return typeof obj !== 'undefined' && obj !== null;
-};
-var hasSymbols = _dereq_('./hasSymbols')();
-var toObject = Object;
-var push = bind.call(Function.call, Array.prototype.push);
-var propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable);
+  /**
+   * Get the component's DOM element
+   * ```js
+   *     var domEl = myComponent.el();
+   * ```
+   *
+   * @return {Element}
+   * @method el
+   */
 
-module.exports = function assign(target, source1) {
-       if (!canBeObject(target)) { throw new TypeError('target must be an object'); }
-       var objTarget = toObject(target);
-       var s, source, i, props, syms, value, key;
-       for (s = 1; s < arguments.length; ++s) {
-               source = toObject(arguments[s]);
-               props = keys(source);
-               if (hasSymbols && Object.getOwnPropertySymbols) {
-                       syms = Object.getOwnPropertySymbols(source);
-                       for (i = 0; i < syms.length; ++i) {
-                               key = syms[i];
-                               if (propIsEnumerable(source, key)) {
-                                       push(props, key);
-                               }
-                       }
-               }
-               for (i = 0; i < props.length; ++i) {
-                       key = props[i];
-                       value = source[key];
-                       if (propIsEnumerable(source, key)) {
-                               objTarget[key] = value;
-                       }
-               }
-       }
-       return objTarget;
-};
 
-},{"./hasSymbols":43,"function-bind":49,"object-keys":50}],45:[function(_dereq_,module,exports){
-'use strict';
+  Component.prototype.el = function el() {
+    return this.el_;
+  };
 
-var defineProperties = _dereq_('define-properties');
+  /**
+   * Create the component's DOM element
+   *
+   * @param  {String=} tagName  Element's node type. e.g. 'div'
+   * @param  {Object=} properties An object of properties that should be set
+   * @param  {Object=} attributes An object of attributes that should be set
+   * @return {Element}
+   * @method createEl
+   */
 
-var implementation = _dereq_('./implementation');
-var getPolyfill = _dereq_('./polyfill');
-var shim = _dereq_('./shim');
 
-defineProperties(implementation, {
-       implementation: implementation,
-       getPolyfill: getPolyfill,
-       shim: shim
-});
+  Component.prototype.createEl = function createEl(tagName, properties, attributes) {
+    return Dom.createEl(tagName, properties, attributes);
+  };
 
-module.exports = implementation;
+  Component.prototype.localize = function localize(string) {
+    var code = this.player_.language && this.player_.language();
+    var languages = this.player_.languages && this.player_.languages();
 
-},{"./implementation":44,"./polyfill":52,"./shim":53,"define-properties":46}],46:[function(_dereq_,module,exports){
-'use strict';
+    if (!code || !languages) {
+      return string;
+    }
 
-var keys = _dereq_('object-keys');
-var foreach = _dereq_('foreach');
-var hasSymbols = typeof Symbol === 'function' && typeof Symbol() === 'symbol';
+    var language = languages[code];
 
-var toStr = Object.prototype.toString;
+    if (language && language[string]) {
+      return language[string];
+    }
 
-var isFunction = function (fn) {
-       return typeof fn === 'function' && toStr.call(fn) === '[object Function]';
-};
+    var primaryCode = code.split('-')[0];
+    var primaryLang = languages[primaryCode];
 
-var arePropertyDescriptorsSupported = function () {
-       var obj = {};
-       try {
-               Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
-        /* eslint-disable no-unused-vars, no-restricted-syntax */
-        for (var _ in obj) { return false; }
-        /* eslint-enable no-unused-vars, no-restricted-syntax */
-               return obj.x === obj;
-       } catch (e) { /* this is IE 8. */
-               return false;
-       }
-};
-var supportsDescriptors = Object.defineProperty && arePropertyDescriptorsSupported();
+    if (primaryLang && primaryLang[string]) {
+      return primaryLang[string];
+    }
 
-var defineProperty = function (object, name, value, predicate) {
-       if (name in object && (!isFunction(predicate) || !predicate())) {
-               return;
-       }
-       if (supportsDescriptors) {
-               Object.defineProperty(object, name, {
-                       configurable: true,
-                       enumerable: false,
-                       value: value,
-                       writable: true
-               });
-       } else {
-               object[name] = value;
-       }
-};
+    return string;
+  };
 
-var defineProperties = function (object, map) {
-       var predicates = arguments.length > 2 ? arguments[2] : {};
-       var props = keys(map);
-       if (hasSymbols) {
-               props = props.concat(Object.getOwnPropertySymbols(map));
-       }
-       foreach(props, function (name) {
-               defineProperty(object, name, map[name], predicates[name]);
-       });
-};
+  /**
+   * Return the component's DOM element where children are inserted.
+   * Will either be the same as el() or a new element defined in createEl().
+   *
+   * @return {Element}
+   * @method contentEl
+   */
 
-defineProperties.supportsDescriptors = !!supportsDescriptors;
 
-module.exports = defineProperties;
+  Component.prototype.contentEl = function contentEl() {
+    return this.contentEl_ || this.el_;
+  };
 
-},{"foreach":47,"object-keys":50}],47:[function(_dereq_,module,exports){
+  /**
+   * Get the component's ID
+   * ```js
+   *     var id = myComponent.id();
+   * ```
+   *
+   * @return {String}
+   * @method id
+   */
 
-var hasOwn = Object.prototype.hasOwnProperty;
-var toString = Object.prototype.toString;
 
-module.exports = function forEach (obj, fn, ctx) {
-    if (toString.call(fn) !== '[object Function]') {
-        throw new TypeError('iterator must be a function');
-    }
-    var l = obj.length;
-    if (l === +l) {
-        for (var i = 0; i < l; i++) {
-            fn.call(ctx, obj[i], i, obj);
-        }
-    } else {
-        for (var k in obj) {
-            if (hasOwn.call(obj, k)) {
-                fn.call(ctx, obj[k], k, obj);
-            }
-        }
-    }
-};
+  Component.prototype.id = function id() {
+    return this.id_;
+  };
 
+  /**
+   * Get the component's name. The name is often used to reference the component.
+   * ```js
+   *     var name = myComponent.name();
+   * ```
+   *
+   * @return {String}
+   * @method name
+   */
 
-},{}],48:[function(_dereq_,module,exports){
-var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible ';
-var slice = Array.prototype.slice;
-var toStr = Object.prototype.toString;
-var funcType = '[object Function]';
 
-module.exports = function bind(that) {
-    var target = this;
-    if (typeof target !== 'function' || toStr.call(target) !== funcType) {
-        throw new TypeError(ERROR_MESSAGE + target);
-    }
-    var args = slice.call(arguments, 1);
+  Component.prototype.name = function name() {
+    return this.name_;
+  };
 
-    var bound;
-    var binder = function () {
-        if (this instanceof bound) {
-            var result = target.apply(
-                this,
-                args.concat(slice.call(arguments))
-            );
-            if (Object(result) === result) {
-                return result;
-            }
-            return this;
-        } else {
-            return target.apply(
-                that,
-                args.concat(slice.call(arguments))
-            );
-        }
-    };
+  /**
+   * Get an array of all child components
+   * ```js
+   *     var kids = myComponent.children();
+   * ```
+   *
+   * @return {Array} The children
+   * @method children
+   */
 
-    var boundLength = Math.max(0, target.length - args.length);
-    var boundArgs = [];
-    for (var i = 0; i < boundLength; i++) {
-        boundArgs.push('$' + i);
-    }
 
-    bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder);
+  Component.prototype.children = function children() {
+    return this.children_;
+  };
 
-    if (target.prototype) {
-        var Empty = function Empty() {};
-        Empty.prototype = target.prototype;
-        bound.prototype = new Empty();
-        Empty.prototype = null;
-    }
+  /**
+   * Returns a child component with the provided ID
+   *
+   * @return {Component}
+   * @method getChildById
+   */
 
-    return bound;
-};
 
-},{}],49:[function(_dereq_,module,exports){
-var implementation = _dereq_('./implementation');
+  Component.prototype.getChildById = function getChildById(id) {
+    return this.childIndex_[id];
+  };
 
-module.exports = Function.prototype.bind || implementation;
+  /**
+   * Returns a child component with the provided name
+   *
+   * @return {Component}
+   * @method getChild
+   */
 
-},{"./implementation":48}],50:[function(_dereq_,module,exports){
-'use strict';
 
-// modified from https://github.com/es-shims/es5-shim
-var has = Object.prototype.hasOwnProperty;
-var toStr = Object.prototype.toString;
-var slice = Array.prototype.slice;
-var isArgs = _dereq_('./isArguments');
-var isEnumerable = Object.prototype.propertyIsEnumerable;
-var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString');
-var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype');
-var dontEnums = [
-       'toString',
-       'toLocaleString',
-       'valueOf',
-       'hasOwnProperty',
-       'isPrototypeOf',
-       'propertyIsEnumerable',
-       'constructor'
-];
-var equalsConstructorPrototype = function (o) {
-       var ctor = o.constructor;
-       return ctor && ctor.prototype === o;
-};
-var excludedKeys = {
-       $console: true,
-       $external: true,
-       $frame: true,
-       $frameElement: true,
-       $frames: true,
-       $innerHeight: true,
-       $innerWidth: true,
-       $outerHeight: true,
-       $outerWidth: true,
-       $pageXOffset: true,
-       $pageYOffset: true,
-       $parent: true,
-       $scrollLeft: true,
-       $scrollTop: true,
-       $scrollX: true,
-       $scrollY: true,
-       $self: true,
-       $webkitIndexedDB: true,
-       $webkitStorageInfo: true,
-       $window: true
-};
-var hasAutomationEqualityBug = (function () {
-       /* global window */
-       if (typeof window === 'undefined') { return false; }
-       for (var k in window) {
-               try {
-                       if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') {
-                               try {
-                                       equalsConstructorPrototype(window[k]);
-                               } catch (e) {
-                                       return true;
-                               }
-                       }
-               } catch (e) {
-                       return true;
-               }
-       }
-       return false;
-}());
-var equalsConstructorPrototypeIfNotBuggy = function (o) {
-       /* global window */
-       if (typeof window === 'undefined' || !hasAutomationEqualityBug) {
-               return equalsConstructorPrototype(o);
-       }
-       try {
-               return equalsConstructorPrototype(o);
-       } catch (e) {
-               return false;
-       }
-};
+  Component.prototype.getChild = function getChild(name) {
+    return this.childNameIndex_[name];
+  };
 
-var keysShim = function keys(object) {
-       var isObject = object !== null && typeof object === 'object';
-       var isFunction = toStr.call(object) === '[object Function]';
-       var isArguments = isArgs(object);
-       var isString = isObject && toStr.call(object) === '[object String]';
-       var theKeys = [];
+  /**
+   * Adds a child component inside this component
+   * ```js
+   *     myComponent.el();
+   *     // -> <div class='my-component'></div>
+   *     myComponent.children();
+   *     // [empty array]
+   *
+   *     var myButton = myComponent.addChild('MyButton');
+   *     // -> <div class='my-component'><div class="my-button">myButton<div></div>
+   *     // -> myButton === myComponent.children()[0];
+   * ```
+   * Pass in options for child constructors and options for children of the child
+   * ```js
+   *     var myButton = myComponent.addChild('MyButton', {
+   *       text: 'Press Me',
+   *       buttonChildExample: {
+   *         buttonChildOption: true
+   *       }
+   *     });
+   * ```
+   *
+   * @param {String|Component} child The class name or instance of a child to add
+   * @param {Object=} options Options, including options to be passed to children of the child.
+   * @param {Number} index into our children array to attempt to add the child
+   * @return {Component} The child component (created by this process if a string was used)
+   * @method addChild
+   */
 
-       if (!isObject && !isFunction && !isArguments) {
-               throw new TypeError('Object.keys called on a non-object');
-       }
 
-       var skipProto = hasProtoEnumBug && isFunction;
-       if (isString && object.length > 0 && !has.call(object, 0)) {
-               for (var i = 0; i < object.length; ++i) {
-                       theKeys.push(String(i));
-               }
-       }
+  Component.prototype.addChild = function addChild(child) {
+    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+    var index = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.children_.length;
 
-       if (isArguments && object.length > 0) {
-               for (var j = 0; j < object.length; ++j) {
-                       theKeys.push(String(j));
-               }
-       } else {
-               for (var name in object) {
-                       if (!(skipProto && name === 'prototype') && has.call(object, name)) {
-                               theKeys.push(String(name));
-                       }
-               }
-       }
+    var component = void 0;
+    var componentName = void 0;
 
-       if (hasDontEnumBug) {
-               var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object);
+    // If child is a string, create nt with options
+    if (typeof child === 'string') {
+      componentName = child;
 
-               for (var k = 0; k < dontEnums.length; ++k) {
-                       if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) {
-                               theKeys.push(dontEnums[k]);
-                       }
-               }
-       }
-       return theKeys;
-};
+      // Options can also be specified as a boolean, so convert to an empty object if false.
+      if (!options) {
+        options = {};
+      }
 
-keysShim.shim = function shimObjectKeys() {
-       if (Object.keys) {
-               var keysWorksWithArguments = (function () {
-                       // Safari 5.0 bug
-                       return (Object.keys(arguments) || '').length === 2;
-               }(1, 2));
-               if (!keysWorksWithArguments) {
-                       var originalKeys = Object.keys;
-                       Object.keys = function keys(object) {
-                               if (isArgs(object)) {
-                                       return originalKeys(slice.call(object));
-                               } else {
-                                       return originalKeys(object);
-                               }
-                       };
-               }
-       } else {
-               Object.keys = keysShim;
-       }
-       return Object.keys || keysShim;
-};
+      // Same as above, but true is deprecated so show a warning.
+      if (options === true) {
+        _log2['default'].warn('Initializing a child component with `true` is deprecated. Children should be defined in an array when possible, but if necessary use an object instead of `true`.');
+        options = {};
+      }
 
-module.exports = keysShim;
+      // If no componentClass in options, assume componentClass is the name lowercased
+      // (e.g. playButton)
+      var componentClassName = options.componentClass || (0, _toTitleCase2['default'])(componentName);
 
-},{"./isArguments":51}],51:[function(_dereq_,module,exports){
-'use strict';
+      // Set name through options
+      options.name = componentName;
 
-var toStr = Object.prototype.toString;
+      // Create a new object & element for this controls set
+      // If there's no .player_, this is a player
+      var ComponentClass = Component.getComponent(componentClassName);
 
-module.exports = function isArguments(value) {
-       var str = toStr.call(value);
-       var isArgs = str === '[object Arguments]';
-       if (!isArgs) {
-               isArgs = str !== '[object Array]' &&
-                       value !== null &&
-                       typeof value === 'object' &&
-                       typeof value.length === 'number' &&
-                       value.length >= 0 &&
-                       toStr.call(value.callee) === '[object Function]';
-       }
-       return isArgs;
-};
-
-},{}],52:[function(_dereq_,module,exports){
-'use strict';
-
-var implementation = _dereq_('./implementation');
+      if (!ComponentClass) {
+        throw new Error('Component ' + componentClassName + ' does not exist');
+      }
 
-var lacksProperEnumerationOrder = function () {
-       if (!Object.assign) {
-               return false;
-       }
-       // v8, specifically in node 4.x, has a bug with incorrect property enumeration order
-       // note: this does not detect the bug unless there's 20 characters
-       var str = 'abcdefghijklmnopqrst';
-       var letters = str.split('');
-       var map = {};
-       for (var i = 0; i < letters.length; ++i) {
-               map[letters[i]] = letters[i];
-       }
-       var obj = Object.assign({}, map);
-       var actual = '';
-       for (var k in obj) {
-               actual += k;
-       }
-       return str !== actual;
-};
+      // data stored directly on the videojs object may be
+      // misidentified as a component to retain
+      // backwards-compatibility with 4.x. check to make sure the
+      // component class can be instantiated.
+      if (typeof ComponentClass !== 'function') {
+        return null;
+      }
 
-var assignHasPendingExceptions = function () {
-       if (!Object.assign || !Object.preventExtensions) {
-               return false;
-       }
-       // Firefox 37 still has "pending exception" logic in its Object.assign implementation,
-       // which is 72% slower than our shim, and Firefox 40's native implementation.
-       var thrower = Object.preventExtensions({ 1: 2 });
-       try {
-               Object.assign(thrower, 'xy');
-       } catch (e) {
-               return thrower[1] === 'y';
-       }
-};
+      component = new ComponentClass(this.player_ || this, options);
 
-module.exports = function getPolyfill() {
-       if (!Object.assign) {
-               return implementation;
-       }
-       if (lacksProperEnumerationOrder()) {
-               return implementation;
-       }
-       if (assignHasPendingExceptions()) {
-               return implementation;
-       }
-       return Object.assign;
-};
+      // child is a component instance
+    } else {
+      component = child;
+    }
 
-},{"./implementation":44}],53:[function(_dereq_,module,exports){
-'use strict';
+    this.children_.splice(index, 0, component);
 
-var define = _dereq_('define-properties');
-var getPolyfill = _dereq_('./polyfill');
+    if (typeof component.id === 'function') {
+      this.childIndex_[component.id()] = component;
+    }
 
-module.exports = function shimAssign() {
-       var polyfill = getPolyfill();
-       define(
-               Object,
-               { assign: polyfill },
-               { assign: function () { return Object.assign !== polyfill; } }
-       );
-       return polyfill;
-};
+    // If a name wasn't used to create the component, check if we can use the
+    // name function of the component
+    componentName = componentName || component.name && component.name();
 
-},{"./polyfill":52,"define-properties":46}],54:[function(_dereq_,module,exports){
-module.exports = SafeParseTuple
+    if (componentName) {
+      this.childNameIndex_[componentName] = component;
+    }
 
-function SafeParseTuple(obj, reviver) {
-    var json
-    var error = null
+    // Add the UI object's element to the container div (box)
+    // Having an element is not required
+    if (typeof component.el === 'function' && component.el()) {
+      var childNodes = this.contentEl().children;
+      var refNode = childNodes[index] || null;
 
-    try {
-        json = JSON.parse(obj, reviver)
-    } catch (err) {
-        error = err
+      this.contentEl().insertBefore(component.el(), refNode);
     }
 
-    return [error, json]
-}
-
-},{}],55:[function(_dereq_,module,exports){
-function clean (s) {
-  return s.replace(/\n\r?\s*/g, '')
-}
+    // Return so it can stored on parent object if desired.
+    return component;
+  };
 
+  /**
+   * Remove a child component from this component's list of children, and the
+   * child component's element from this component's element
+   *
+   * @param  {Component} component Component to remove
+   * @method removeChild
+   */
 
-module.exports = function tsml (sa) {
-  var s = ''
-    , i = 0
 
-  for (; i < arguments.length; i++)
-    s += clean(sa[i]) + (arguments[i + 1] || '')
+  Component.prototype.removeChild = function removeChild(component) {
+    if (typeof component === 'string') {
+      component = this.getChild(component);
+    }
 
-  return s
-}
-},{}],56:[function(_dereq_,module,exports){
-"use strict";
-var window = _dereq_("global/window")
-var once = _dereq_("once")
-var isFunction = _dereq_("is-function")
-var parseHeaders = _dereq_("parse-headers")
-var xtend = _dereq_("xtend")
+    if (!component || !this.children_) {
+      return;
+    }
 
-module.exports = createXHR
-createXHR.XMLHttpRequest = window.XMLHttpRequest || noop
-createXHR.XDomainRequest = "withCredentials" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest
+    var childFound = false;
 
-forEachArray(["get", "put", "post", "patch", "head", "delete"], function(method) {
-    createXHR[method === "delete" ? "del" : method] = function(uri, options, callback) {
-        options = initParams(uri, options, callback)
-        options.method = method.toUpperCase()
-        return _createXHR(options)
+    for (var i = this.children_.length - 1; i >= 0; i--) {
+      if (this.children_[i] === component) {
+        childFound = true;
+        this.children_.splice(i, 1);
+        break;
+      }
     }
-})
 
-function forEachArray(array, iterator) {
-    for (var i = 0; i < array.length; i++) {
-        iterator(array[i])
+    if (!childFound) {
+      return;
     }
-}
 
-function isEmpty(obj){
-    for(var i in obj){
-        if(obj.hasOwnProperty(i)) return false
-    }
-    return true
-}
+    this.childIndex_[component.id()] = null;
+    this.childNameIndex_[component.name()] = null;
 
-function initParams(uri, options, callback) {
-    var params = uri
+    var compEl = component.el();
 
-    if (isFunction(options)) {
-        callback = options
-        if (typeof uri === "string") {
-            params = {uri:uri}
-        }
-    } else {
-        params = xtend(options, {uri: uri})
+    if (compEl && compEl.parentNode === this.contentEl()) {
+      this.contentEl().removeChild(component.el());
     }
+  };
 
-    params.callback = callback
-    return params
-}
+  /**
+   * Add and initialize default child components from options
+   * ```js
+   *     // when an instance of MyComponent is created, all children in options
+   *     // will be added to the instance by their name strings and options
+   *     MyComponent.prototype.options_ = {
+   *       children: [
+   *         'myChildComponent'
+   *       ],
+   *       myChildComponent: {
+   *         myChildOption: true
+   *       }
+   *     };
+   *
+   *     // Or when creating the component
+   *     var myComp = new MyComponent(player, {
+   *       children: [
+   *         'myChildComponent'
+   *       ],
+   *       myChildComponent: {
+   *         myChildOption: true
+   *       }
+   *     });
+   * ```
+   * The children option can also be an array of
+   * child options objects (that also include a 'name' key).
+   * This can be used if you have two child components of the
+   * same type that need different options.
+   * ```js
+   *     var myComp = new MyComponent(player, {
+   *       children: [
+   *         'button',
+   *         {
+   *           name: 'button',
+   *           someOtherOption: true
+   *         },
+   *         {
+   *           name: 'button',
+   *           someOtherOption: false
+   *         }
+   *       ]
+   *     });
+   * ```
+   *
+   * @method initChildren
+   */
 
-function createXHR(uri, options, callback) {
-    options = initParams(uri, options, callback)
-    return _createXHR(options)
-}
 
-function _createXHR(options) {
-    var callback = options.callback
-    if(typeof callback === "undefined"){
-        throw new Error("callback argument missing")
-    }
-    callback = once(callback)
+  Component.prototype.initChildren = function initChildren() {
+    var _this = this;
 
-    function readystatechange() {
-        if (xhr.readyState === 4) {
-            loadFunc()
-        }
-    }
+    var children = this.options_.children;
 
-    function getBody() {
-        // Chrome with requestType=blob throws errors arround when even testing access to responseText
-        var body = undefined
+    if (children) {
+      (function () {
+        // `this` is `parent`
+        var parentOptions = _this.options_;
 
-        if (xhr.response) {
-            body = xhr.response
-        } else if (xhr.responseType === "text" || !xhr.responseType) {
-            body = xhr.responseText || xhr.responseXML
-        }
+        var handleAdd = function handleAdd(child) {
+          var name = child.name;
+          var opts = child.opts;
 
-        if (isJson) {
-            try {
-                body = JSON.parse(body)
-            } catch (e) {}
-        }
+          // Allow options for children to be set at the parent options
+          // e.g. videojs(id, { controlBar: false });
+          // instead of videojs(id, { children: { controlBar: false });
+          if (parentOptions[name] !== undefined) {
+            opts = parentOptions[name];
+          }
 
-        return body
-    }
+          // Allow for disabling default components
+          // e.g. options['children']['posterImage'] = false
+          if (opts === false) {
+            return;
+          }
 
-    var failureResponse = {
-                body: undefined,
-                headers: {},
-                statusCode: 0,
-                method: method,
-                url: uri,
-                rawRequest: xhr
-            }
+          // Allow options to be passed as a simple boolean if no configuration
+          // is necessary.
+          if (opts === true) {
+            opts = {};
+          }
 
-    function errorFunc(evt) {
-        clearTimeout(timeoutTimer)
-        if(!(evt instanceof Error)){
-            evt = new Error("" + (evt || "Unknown XMLHttpRequest Error") )
-        }
-        evt.statusCode = 0
-        callback(evt, failureResponse)
-    }
+          // We also want to pass the original player options to each component as well so they don't need to
+          // reach back into the player for options later.
+          opts.playerOptions = _this.options_.playerOptions;
 
-    // will load the data & process the response in a special response object
-    function loadFunc() {
-        if (aborted) return
-        var status
-        clearTimeout(timeoutTimer)
-        if(options.useXDR && xhr.status===undefined) {
-            //IE8 CORS GET successful response doesn't have a status field, but body is fine
-            status = 200
+          // Create and add the child component.
+          // Add a direct reference to the child by name on the parent instance.
+          // If two of the same component are used, different names should be supplied
+          // for each
+          var newChild = _this.addChild(name, opts);
+
+          if (newChild) {
+            _this[name] = newChild;
+          }
+        };
+
+        // Allow for an array of children details to passed in the options
+        var workingChildren = void 0;
+        var Tech = Component.getComponent('Tech');
+
+        if (Array.isArray(children)) {
+          workingChildren = children;
         } else {
-            status = (xhr.status === 1223 ? 204 : xhr.status)
+          workingChildren = Object.keys(children);
         }
-        var response = failureResponse
-        var err = null
 
-        if (status !== 0){
-            response = {
-                body: getBody(),
-                statusCode: status,
-                method: method,
-                headers: {},
-                url: uri,
-                rawRequest: xhr
-            }
-            if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE
-                response.headers = parseHeaders(xhr.getAllResponseHeaders())
+        workingChildren
+        // children that are in this.options_ but also in workingChildren  would
+        // give us extra children we do not want. So, we want to filter them out.
+        .concat(Object.keys(_this.options_).filter(function (child) {
+          return !workingChildren.some(function (wchild) {
+            if (typeof wchild === 'string') {
+              return child === wchild;
             }
-        } else {
-            err = new Error("Internal XMLHttpRequest Error")
-        }
-        callback(err, response, response.body)
+            return child === wchild.name;
+          });
+        })).map(function (child) {
+          var name = void 0;
+          var opts = void 0;
 
-    }
+          if (typeof child === 'string') {
+            name = child;
+            opts = children[name] || _this.options_[name] || {};
+          } else {
+            name = child.name;
+            opts = child;
+          }
 
-    var xhr = options.xhr || null
+          return { name: name, opts: opts };
+        }).filter(function (child) {
+          // we have to make sure that child.name isn't in the techOrder since
+          // techs are registerd as Components but can't aren't compatible
+          // See https://github.com/videojs/video.js/issues/2772
+          var c = Component.getComponent(child.opts.componentClass || (0, _toTitleCase2['default'])(child.name));
 
-    if (!xhr) {
-        if (options.cors || options.useXDR) {
-            xhr = new createXHR.XDomainRequest()
-        }else{
-            xhr = new createXHR.XMLHttpRequest()
-        }
+          return c && !Tech.isTech(c);
+        }).forEach(handleAdd);
+      })();
     }
+  };
 
-    var key
-    var aborted
-    var uri = xhr.url = options.uri || options.url
-    var method = xhr.method = options.method || "GET"
-    var body = options.body || options.data || null
-    var headers = xhr.headers = options.headers || {}
-    var sync = !!options.sync
-    var isJson = false
-    var timeoutTimer
+  /**
+   * Allows sub components to stack CSS class names
+   *
+   * @return {String} The constructed class name
+   * @method buildCSSClass
+   */
 
-    if ("json" in options) {
-        isJson = true
-        headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user
-        if (method !== "GET" && method !== "HEAD") {
-            headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user
-            body = JSON.stringify(options.json)
-        }
-    }
 
-    xhr.onreadystatechange = readystatechange
-    xhr.onload = loadFunc
-    xhr.onerror = errorFunc
-    // IE9 must have onprogress be set to a unique function.
-    xhr.onprogress = function () {
-        // IE must die
-    }
-    xhr.ontimeout = errorFunc
-    xhr.open(method, uri, !sync, options.username, options.password)
-    //has to be after open
-    if(!sync) {
-        xhr.withCredentials = !!options.withCredentials
-    }
-    // Cannot set timeout with sync request
-    // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly
-    // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
-    if (!sync && options.timeout > 0 ) {
-        timeoutTimer = setTimeout(function(){
-            aborted=true//IE9 may still call readystatechange
-            xhr.abort("timeout")
-            var e = new Error("XMLHttpRequest timeout")
-            e.code = "ETIMEDOUT"
-            errorFunc(e)
-        }, options.timeout )
-    }
+  Component.prototype.buildCSSClass = function buildCSSClass() {
+    // Child classes can include a function that does:
+    // return 'CLASS NAME' + this._super();
+    return '';
+  };
 
-    if (xhr.setRequestHeader) {
-        for(key in headers){
-            if(headers.hasOwnProperty(key)){
-                xhr.setRequestHeader(key, headers[key])
-            }
-        }
-    } else if (options.headers && !isEmpty(options.headers)) {
-        throw new Error("Headers cannot be set on an XDomainRequest object")
-    }
+  /**
+   * Add an event listener to this component's element
+   * ```js
+   *     var myFunc = function() {
+   *       var myComponent = this;
+   *       // Do something when the event is fired
+   *     };
+   *
+   *     myComponent.on('eventType', myFunc);
+   * ```
+   * The context of myFunc will be myComponent unless previously bound.
+   * Alternatively, you can add a listener to another element or component.
+   * ```js
+   *     myComponent.on(otherElement, 'eventName', myFunc);
+   *     myComponent.on(otherComponent, 'eventName', myFunc);
+   * ```
+   * The benefit of using this over `VjsEvents.on(otherElement, 'eventName', myFunc)`
+   * and `otherComponent.on('eventName', myFunc)` is that this way the listeners
+   * will be automatically cleaned up when either component is disposed.
+   * It will also bind myComponent as the context of myFunc.
+   * **NOTE**: When using this on elements in the page other than window
+   * and document (both permanent), if you remove the element from the DOM
+   * you need to call `myComponent.trigger(el, 'dispose')` on it to clean up
+   * references to it and allow the browser to garbage collect it.
+   *
+   * @param  {String|Component} first   The event type or other component
+   * @param  {Function|String}      second  The event handler or event type
+   * @param  {Function}             third   The event handler
+   * @return {Component}
+   * @method on
+   */
 
-    if ("responseType" in options) {
-        xhr.responseType = options.responseType
-    }
 
-    if ("beforeSend" in options &&
-        typeof options.beforeSend === "function"
-    ) {
-        options.beforeSend(xhr)
-    }
+  Component.prototype.on = function on(first, second, third) {
+    var _this2 = this;
 
-    xhr.send(body)
+    if (typeof first === 'string' || Array.isArray(first)) {
+      Events.on(this.el_, first, Fn.bind(this, second));
 
-    return xhr
+      // Targeting another component or element
+    } else {
+      (function () {
+        var target = first;
+        var type = second;
+        var fn = Fn.bind(_this2, third);
 
+        // When this component is disposed, remove the listener from the other component
+        var removeOnDispose = function removeOnDispose() {
+          return _this2.off(target, type, fn);
+        };
 
-}
+        // Use the same function ID so we can remove it later it using the ID
+        // of the original listener
+        removeOnDispose.guid = fn.guid;
+        _this2.on('dispose', removeOnDispose);
 
-function noop() {}
+        // If the other component is disposed first we need to clean the reference
+        // to the other component in this component's removeOnDispose listener
+        // Otherwise we create a memory leak.
+        var cleanRemover = function cleanRemover() {
+          return _this2.off('dispose', removeOnDispose);
+        };
 
-},{"global/window":2,"is-function":57,"once":58,"parse-headers":61,"xtend":62}],57:[function(_dereq_,module,exports){
-module.exports = isFunction
+        // Add the same function ID so we can easily remove it later
+        cleanRemover.guid = fn.guid;
+
+        // Check if this is a DOM node
+        if (first.nodeName) {
+          // Add the listener to the other element
+          Events.on(target, type, fn);
+          Events.on(target, 'dispose', cleanRemover);
+
+          // Should be a component
+          // Not using `instanceof Component` because it makes mock players difficult
+        } else if (typeof first.on === 'function') {
+          // Add the listener to the other component
+          target.on(type, fn);
+          target.on('dispose', cleanRemover);
+        }
+      })();
+    }
 
-var toString = Object.prototype.toString
+    return this;
+  };
 
-function isFunction (fn) {
-  var string = toString.call(fn)
-  return string === '[object Function]' ||
-    (typeof fn === 'function' && string !== '[object RegExp]') ||
-    (typeof window !== 'undefined' &&
-     // IE8 and below
-     (fn === window.setTimeout ||
-      fn === window.alert ||
-      fn === window.confirm ||
-      fn === window.prompt))
-};
-
-},{}],58:[function(_dereq_,module,exports){
-module.exports = once
-
-once.proto = once(function () {
-  Object.defineProperty(Function.prototype, 'once', {
-    value: function () {
-      return once(this)
-    },
-    configurable: true
-  })
-})
-
-function once (fn) {
-  var called = false
-  return function () {
-    if (called) return
-    called = true
-    return fn.apply(this, arguments)
-  }
-}
-
-},{}],59:[function(_dereq_,module,exports){
-var isFunction = _dereq_('is-function')
-
-module.exports = forEach
+  /**
+   * Remove an event listener from this component's element
+   * ```js
+   *     myComponent.off('eventType', myFunc);
+   * ```
+   * If myFunc is excluded, ALL listeners for the event type will be removed.
+   * If eventType is excluded, ALL listeners will be removed from the component.
+   * Alternatively you can use `off` to remove listeners that were added to other
+   * elements or components using `myComponent.on(otherComponent...`.
+   * In this case both the event type and listener function are REQUIRED.
+   * ```js
+   *     myComponent.off(otherElement, 'eventType', myFunc);
+   *     myComponent.off(otherComponent, 'eventType', myFunc);
+   * ```
+   *
+   * @param  {String=|Component}  first  The event type or other component
+   * @param  {Function=|String}       second The listener function or event type
+   * @param  {Function=}              third  The listener for other component
+   * @return {Component}
+   * @method off
+   */
 
-var toString = Object.prototype.toString
-var hasOwnProperty = Object.prototype.hasOwnProperty
 
-function forEach(list, iterator, context) {
-    if (!isFunction(iterator)) {
-        throw new TypeError('iterator must be a function')
-    }
+  Component.prototype.off = function off(first, second, third) {
+    if (!first || typeof first === 'string' || Array.isArray(first)) {
+      Events.off(this.el_, first, second);
+    } else {
+      var target = first;
+      var type = second;
+      // Ensure there's at least a guid, even if the function hasn't been used
+      var fn = Fn.bind(this, third);
 
-    if (arguments.length < 3) {
-        context = this
-    }
-    
-    if (toString.call(list) === '[object Array]')
-        forEachArray(list, iterator, context)
-    else if (typeof list === 'string')
-        forEachString(list, iterator, context)
-    else
-        forEachObject(list, iterator, context)
-}
+      // Remove the dispose listener on this component,
+      // which was given the same guid as the event listener
+      this.off('dispose', fn);
 
-function forEachArray(array, iterator, context) {
-    for (var i = 0, len = array.length; i < len; i++) {
-        if (hasOwnProperty.call(array, i)) {
-            iterator.call(context, array[i], i, array)
-        }
+      if (first.nodeName) {
+        // Remove the listener
+        Events.off(target, type, fn);
+        // Remove the listener for cleaning the dispose listener
+        Events.off(target, 'dispose', fn);
+      } else {
+        target.off(type, fn);
+        target.off('dispose', fn);
+      }
     }
-}
 
-function forEachString(string, iterator, context) {
-    for (var i = 0, len = string.length; i < len; i++) {
-        // no such thing as a sparse string.
-        iterator.call(context, string.charAt(i), i, string)
-    }
-}
+    return this;
+  };
 
-function forEachObject(object, iterator, context) {
-    for (var k in object) {
-        if (hasOwnProperty.call(object, k)) {
-            iterator.call(context, object[k], k, object)
-        }
-    }
-}
+  /**
+   * Add an event listener to be triggered only once and then removed
+   * ```js
+   *     myComponent.one('eventName', myFunc);
+   * ```
+   * Alternatively you can add a listener to another element or component
+   * that will be triggered only once.
+   * ```js
+   *     myComponent.one(otherElement, 'eventName', myFunc);
+   *     myComponent.one(otherComponent, 'eventName', myFunc);
+   * ```
+   *
+   * @param  {String|Component}  first   The event type or other component
+   * @param  {Function|String}       second  The listener function or event type
+   * @param  {Function=}             third   The listener function for other component
+   * @return {Component}
+   * @method one
+   */
 
-},{"is-function":57}],60:[function(_dereq_,module,exports){
 
-exports = module.exports = trim;
+  Component.prototype.one = function one(first, second, third) {
+    var _this3 = this,
+        _arguments = arguments;
 
-function trim(str){
-  return str.replace(/^\s*|\s*$/g, '');
-}
+    if (typeof first === 'string' || Array.isArray(first)) {
+      Events.one(this.el_, first, Fn.bind(this, second));
+    } else {
+      (function () {
+        var target = first;
+        var type = second;
+        var fn = Fn.bind(_this3, third);
 
-exports.left = function(str){
-  return str.replace(/^\s*/, '');
-};
+        var newFunc = function newFunc() {
+          _this3.off(target, type, newFunc);
+          fn.apply(null, _arguments);
+        };
 
-exports.right = function(str){
-  return str.replace(/\s*$/, '');
-};
+        // Keep the same function ID so we can remove it later
+        newFunc.guid = fn.guid;
 
-},{}],61:[function(_dereq_,module,exports){
-var trim = _dereq_('trim')
-  , forEach = _dereq_('for-each')
-  , isArray = function(arg) {
-      return Object.prototype.toString.call(arg) === '[object Array]';
+        _this3.on(target, type, newFunc);
+      })();
     }
 
-module.exports = function (headers) {
-  if (!headers)
-    return {}
-
-  var result = {}
+    return this;
+  };
 
-  forEach(
-      trim(headers).split('\n')
-    , function (row) {
-        var index = row.indexOf(':')
-          , key = trim(row.slice(0, index)).toLowerCase()
-          , value = trim(row.slice(index + 1))
+  /**
+   * Trigger an event on an element
+   * ```js
+   *     myComponent.trigger('eventName');
+   *     myComponent.trigger({'type':'eventName'});
+   *     myComponent.trigger('eventName', {data: 'some data'});
+   *     myComponent.trigger({'type':'eventName'}, {data: 'some data'});
+   * ```
+   *
+   * @param  {Event|Object|String} event  A string (the type) or an event object with a type attribute
+   * @param  {Object} [hash] data hash to pass along with the event
+   * @return {Component}       self
+   * @method trigger
+   */
 
-        if (typeof(result[key]) === 'undefined') {
-          result[key] = value
-        } else if (isArray(result[key])) {
-          result[key].push(value)
-        } else {
-          result[key] = [ result[key], value ]
-        }
-      }
-  )
 
-  return result
-}
-},{"for-each":59,"trim":60}],62:[function(_dereq_,module,exports){
-module.exports = extend
+  Component.prototype.trigger = function trigger(event, hash) {
+    Events.trigger(this.el_, event, hash);
+    return this;
+  };
 
-var hasOwnProperty = Object.prototype.hasOwnProperty;
+  /**
+   * Bind a listener to the component's ready state.
+   * Different from event listeners in that if the ready event has already happened
+   * it will trigger the function immediately.
+   *
+   * @param  {Function} fn Ready listener
+   * @param  {Boolean} sync Exec the listener synchronously if component is ready
+   * @return {Component}
+   * @method ready
+   */
 
-function extend() {
-    var target = {}
 
-    for (var i = 0; i < arguments.length; i++) {
-        var source = arguments[i]
+  Component.prototype.ready = function ready(fn) {
+    var sync = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
 
-        for (var key in source) {
-            if (hasOwnProperty.call(source, key)) {
-                target[key] = source[key]
-            }
+    if (fn) {
+      if (this.isReady_) {
+        if (sync) {
+          fn.call(this);
+        } else {
+          // Call the function asynchronously by default for consistency
+          this.setTimeout(fn, 1);
         }
+      } else {
+        this.readyQueue_ = this.readyQueue_ || [];
+        this.readyQueue_.push(fn);
+      }
     }
+    return this;
+  };
 
-    return target
-}
-
-},{}],63:[function(_dereq_,module,exports){
-/**
- * @file big-play-button.js
- */
-'use strict';
-
-exports.__esModule = true;
+  /**
+   * Trigger the ready listeners
+   *
+   * @return {Component}
+   * @method triggerReady
+   */
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+  Component.prototype.triggerReady = function triggerReady() {
+    this.isReady_ = true;
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+    // Ensure ready is triggerd asynchronously
+    this.setTimeout(function () {
+      var readyQueue = this.readyQueue_;
 
-var _buttonJs = _dereq_('./button.js');
+      // Reset Ready Queue
+      this.readyQueue_ = [];
 
-var _buttonJs2 = _interopRequireDefault(_buttonJs);
+      if (readyQueue && readyQueue.length > 0) {
+        readyQueue.forEach(function (fn) {
+          fn.call(this);
+        }, this);
+      }
 
-var _componentJs = _dereq_('./component.js');
-
-var _componentJs2 = _interopRequireDefault(_componentJs);
-
-/**
- * Initial play button. Shows before the video has played. The hiding of the
- * big play button is done via CSS and player states.
- *
- * @param {Object} player  Main Player
- * @param {Object=} options Object of option names and values
- * @extends Button
- * @class BigPlayButton
- */
-
-var BigPlayButton = (function (_Button) {
-  _inherits(BigPlayButton, _Button);
-
-  function BigPlayButton(player, options) {
-    _classCallCheck(this, BigPlayButton);
-
-    _Button.call(this, player, options);
-  }
+      // Allow for using event listeners also
+      this.trigger('ready');
+    }, 1);
+  };
 
   /**
-   * Allow sub components to stack CSS class names
+   * Finds a single DOM element matching `selector` within the component's
+   * `contentEl` or another custom context.
    *
-   * @return {String} The constructed class name
-   * @method buildCSSClass
+   * @method $
+   * @param  {String} selector
+   *         A valid CSS selector, which will be passed to `querySelector`.
+   *
+   * @param  {Element|String} [context=document]
+   *         A DOM element within which to query. Can also be a selector
+   *         string in which case the first matching element will be used
+   *         as context. If missing (or no element matches selector), falls
+   *         back to `document`.
+   *
+   * @return {Element|null}
    */
 
-  BigPlayButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-big-play-button';
+
+  Component.prototype.$ = function $(selector, context) {
+    return Dom.$(selector, context || this.contentEl());
   };
 
   /**
-   * Handles click for play
+   * Finds a all DOM elements matching `selector` within the component's
+   * `contentEl` or another custom context.
    *
-   * @method handleClick
+   * @method $$
+   * @param  {String} selector
+   *         A valid CSS selector, which will be passed to `querySelectorAll`.
+   *
+   * @param  {Element|String} [context=document]
+   *         A DOM element within which to query. Can also be a selector
+   *         string in which case the first matching element will be used
+   *         as context. If missing (or no element matches selector), falls
+   *         back to `document`.
+   *
+   * @return {NodeList}
    */
 
-  BigPlayButton.prototype.handleClick = function handleClick() {
-    this.player_.play();
-  };
-
-  return BigPlayButton;
-})(_buttonJs2['default']);
-
-BigPlayButton.prototype.controlText_ = 'Play Video';
-
-_componentJs2['default'].registerComponent('BigPlayButton', BigPlayButton);
-exports['default'] = BigPlayButton;
-module.exports = exports['default'];
-
-},{"./button.js":64,"./component.js":67}],64:[function(_dereq_,module,exports){
-/**
- * @file button.js
- */
-'use strict';
-
-exports.__esModule = true;
-
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+  Component.prototype.$$ = function $$(selector, context) {
+    return Dom.$$(selector, context || this.contentEl());
+  };
 
-var _clickableComponentJs = _dereq_('./clickable-component.js');
+  /**
+   * Check if a component's element has a CSS class name
+   *
+   * @param {String} classToCheck Classname to check
+   * @return {Component}
+   * @method hasClass
+   */
 
-var _clickableComponentJs2 = _interopRequireDefault(_clickableComponentJs);
 
-var _component = _dereq_('./component');
+  Component.prototype.hasClass = function hasClass(classToCheck) {
+    return Dom.hasElClass(this.el_, classToCheck);
+  };
 
-var _component2 = _interopRequireDefault(_component);
+  /**
+   * Add a CSS class name to the component's element
+   *
+   * @param {String} classToAdd Classname to add
+   * @return {Component}
+   * @method addClass
+   */
 
-var _utilsEventsJs = _dereq_('./utils/events.js');
 
-var Events = _interopRequireWildcard(_utilsEventsJs);
+  Component.prototype.addClass = function addClass(classToAdd) {
+    Dom.addElClass(this.el_, classToAdd);
+    return this;
+  };
 
-var _utilsFnJs = _dereq_('./utils/fn.js');
+  /**
+   * Remove a CSS class name from the component's element
+   *
+   * @param {String} classToRemove Classname to remove
+   * @return {Component}
+   * @method removeClass
+   */
 
-var Fn = _interopRequireWildcard(_utilsFnJs);
 
-var _utilsLogJs = _dereq_('./utils/log.js');
+  Component.prototype.removeClass = function removeClass(classToRemove) {
+    Dom.removeElClass(this.el_, classToRemove);
+    return this;
+  };
 
-var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs);
+  /**
+   * Add or remove a CSS class name from the component's element
+   *
+   * @param  {String} classToToggle
+   * @param  {Boolean|Function} [predicate]
+   *         Can be a function that returns a Boolean. If `true`, the class
+   *         will be added; if `false`, the class will be removed. If not
+   *         given, the class will be added if not present and vice versa.
+   *
+   * @return {Component}
+   * @method toggleClass
+   */
 
-var _globalDocument = _dereq_('global/document');
 
-var _globalDocument2 = _interopRequireDefault(_globalDocument);
+  Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) {
+    Dom.toggleElClass(this.el_, classToToggle, predicate);
+    return this;
+  };
 
-var _objectAssign = _dereq_('object.assign');
+  /**
+   * Show the component element if hidden
+   *
+   * @return {Component}
+   * @method show
+   */
 
-var _objectAssign2 = _interopRequireDefault(_objectAssign);
 
-/**
- * Base class for all buttons
- *
- * @param {Object} player  Main Player
- * @param {Object=} options Object of option names and values
- * @extends ClickableComponent
- * @class Button
- */
+  Component.prototype.show = function show() {
+    this.removeClass('vjs-hidden');
+    return this;
+  };
 
-var Button = (function (_ClickableComponent) {
-  _inherits(Button, _ClickableComponent);
+  /**
+   * Hide the component element if currently showing
+   *
+   * @return {Component}
+   * @method hide
+   */
 
-  function Button(player, options) {
-    _classCallCheck(this, Button);
 
-    _ClickableComponent.call(this, player, options);
-  }
+  Component.prototype.hide = function hide() {
+    this.addClass('vjs-hidden');
+    return this;
+  };
 
   /**
-   * Create the component's DOM element
+   * Lock an item in its visible state
+   * To be used with fadeIn/fadeOut.
    *
-   * @param {String=} type Element's node type. e.g. 'div'
-   * @param {Object=} props An object of properties that should be set on the element
-   * @param {Object=} attributes An object of attributes that should be set on the element
-   * @return {Element}
-   * @method createEl
+   * @return {Component}
+   * @private
+   * @method lockShowing
    */
 
-  Button.prototype.createEl = function createEl() {
-    var tag = arguments.length <= 0 || arguments[0] === undefined ? 'button' : arguments[0];
-    var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-    var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
-
-    props = _objectAssign2['default']({
-      className: this.buildCSSClass()
-    }, props);
 
-    if (tag !== 'button') {
-      _utilsLogJs2['default'].warn('Creating a Button with an HTML element of ' + tag + ' is deprecated; use ClickableComponent instead.');
+  Component.prototype.lockShowing = function lockShowing() {
+    this.addClass('vjs-lock-showing');
+    return this;
+  };
 
-      // Add properties for clickable element which is not a native HTML button
-      props = _objectAssign2['default']({
-        tabIndex: 0
-      }, props);
+  /**
+   * Unlock an item to be hidden
+   * To be used with fadeIn/fadeOut.
+   *
+   * @return {Component}
+   * @private
+   * @method unlockShowing
+   */
 
-      // Add ARIA attributes for clickable element which is not a native HTML button
-      attributes = _objectAssign2['default']({
-        role: 'button'
-      }, attributes);
-    }
 
-    // Add attributes for button element
-    attributes = _objectAssign2['default']({
-      type: 'button', // Necessary since the default button type is "submit"
-      'aria-live': 'polite' // let the screen reader user know that the text of the button may change
-    }, attributes);
+  Component.prototype.unlockShowing = function unlockShowing() {
+    this.removeClass('vjs-lock-showing');
+    return this;
+  };
 
-    var el = _component2['default'].prototype.createEl.call(this, tag, props, attributes);
+  /**
+   * Set or get the width of the component (CSS values)
+   * Setting the video tag dimension values only works with values in pixels.
+   * Percent values will not work.
+   * Some percents can be used, but width()/height() will return the number + %,
+   * not the actual computed width/height.
+   *
+   * @param  {Number|String=} num   Optional width number
+   * @param  {Boolean} skipListeners Skip the 'resize' event trigger
+   * @return {Component} This component, when setting the width
+   * @return {Number|String} The width, when getting
+   * @method width
+   */
 
-    this.createControlTextEl(el);
 
-    return el;
+  Component.prototype.width = function width(num, skipListeners) {
+    return this.dimension('width', num, skipListeners);
   };
 
   /**
-   * Adds a child component inside this button
+   * Get or set the height of the component (CSS values)
+   * Setting the video tag dimension values only works with values in pixels.
+   * Percent values will not work.
+   * Some percents can be used, but width()/height() will return the number + %,
+   * not the actual computed width/height.
    *
-   * @param {String|Component} child The class name or instance of a child to add
-   * @param {Object=} options Options, including options to be passed to children of the child.
-   * @return {Component} The child component (created by this process if a string was used)
-   * @deprecated
-   * @method addChild
+   * @param  {Number|String=} num     New component height
+   * @param  {Boolean=} skipListeners Skip the resize event trigger
+   * @return {Component} This component, when setting the height
+   * @return {Number|String} The height, when getting
+   * @method height
    */
 
-  Button.prototype.addChild = function addChild(child) {
-    var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-
-    var className = this.constructor.name;
-    _utilsLogJs2['default'].warn('Adding an actionable (user controllable) child to a Button (' + className + ') is not supported; use a ClickableComponent instead.');
 
-    // Avoid the error message generated by ClickableComponent's addChild method
-    return _component2['default'].prototype.addChild.call(this, child, options);
+  Component.prototype.height = function height(num, skipListeners) {
+    return this.dimension('height', num, skipListeners);
   };
 
   /**
-   * Handle KeyPress (document level) - Extend with specific functionality for button
+   * Set both width and height at the same time
    *
-   * @method handleKeyPress
+   * @param  {Number|String} width Width of player
+   * @param  {Number|String} height Height of player
+   * @return {Component} The component
+   * @method dimensions
    */
 
-  Button.prototype.handleKeyPress = function handleKeyPress(event) {
-    // Ignore Space (32) or Enter (13) key operation, which is handled by the browser for a button.
-    if (event.which === 32 || event.which === 13) {} else {
-      _ClickableComponent.prototype.handleKeyPress.call(this, event); // Pass keypress handling up for unsupported keys
-    }
-  };
 
-  return Button;
-})(_clickableComponentJs2['default']);
-
-_component2['default'].registerComponent('Button', Button);
-exports['default'] = Button;
-module.exports = exports['default'];
-
-},{"./clickable-component.js":65,"./component":67,"./utils/events.js":143,"./utils/fn.js":144,"./utils/log.js":147,"global/document":1,"object.assign":45}],65:[function(_dereq_,module,exports){
-/**
- * @file button.js
- */
-'use strict';
-
-exports.__esModule = true;
-
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-var _component = _dereq_('./component');
-
-var _component2 = _interopRequireDefault(_component);
-
-var _utilsDomJs = _dereq_('./utils/dom.js');
-
-var Dom = _interopRequireWildcard(_utilsDomJs);
-
-var _utilsEventsJs = _dereq_('./utils/events.js');
-
-var Events = _interopRequireWildcard(_utilsEventsJs);
-
-var _utilsFnJs = _dereq_('./utils/fn.js');
-
-var Fn = _interopRequireWildcard(_utilsFnJs);
-
-var _utilsLogJs = _dereq_('./utils/log.js');
-
-var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs);
+  Component.prototype.dimensions = function dimensions(width, height) {
+    // Skip resize listeners on width for optimization
+    return this.width(width, true).height(height);
+  };
 
-var _globalDocument = _dereq_('global/document');
+  /**
+   * Get or set width or height
+   * This is the shared code for the width() and height() methods.
+   * All for an integer, integer + 'px' or integer + '%';
+   * Known issue: Hidden elements officially have a width of 0. We're defaulting
+   * to the style.width value and falling back to computedStyle which has the
+   * hidden element issue. Info, but probably not an efficient fix:
+   * http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/
+   *
+   * @param  {String} widthOrHeight  'width' or 'height'
+   * @param  {Number|String=} num     New dimension
+   * @param  {Boolean=} skipListeners Skip resize event trigger
+   * @return {Component} The component if a dimension was set
+   * @return {Number|String} The dimension if nothing was set
+   * @private
+   * @method dimension
+   */
 
-var _globalDocument2 = _interopRequireDefault(_globalDocument);
 
-var _objectAssign = _dereq_('object.assign');
+  Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) {
+    if (num !== undefined) {
+      // Set to zero if null or literally NaN (NaN !== NaN)
+      if (num === null || num !== num) {
+        num = 0;
+      }
 
-var _objectAssign2 = _interopRequireDefault(_objectAssign);
+      // Check if using css width/height (% or px) and adjust
+      if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
+        this.el_.style[widthOrHeight] = num;
+      } else if (num === 'auto') {
+        this.el_.style[widthOrHeight] = '';
+      } else {
+        this.el_.style[widthOrHeight] = num + 'px';
+      }
 
-/**
- * Clickable Component which is clickable or keyboard actionable, but is not a native HTML button
- *
- * @param {Object} player  Main Player
- * @param {Object=} options Object of option names and values
- * @extends Component
- * @class ClickableComponent
- */
+      // skipListeners allows us to avoid triggering the resize event when setting both width and height
+      if (!skipListeners) {
+        this.trigger('resize');
+      }
 
-var ClickableComponent = (function (_Component) {
-  _inherits(ClickableComponent, _Component);
+      // Return component
+      return this;
+    }
 
-  function ClickableComponent(player, options) {
-    _classCallCheck(this, ClickableComponent);
+    // Not setting a value, so getting it
+    // Make sure element exists
+    if (!this.el_) {
+      return 0;
+    }
 
-    _Component.call(this, player, options);
+    // Get dimension value from style
+    var val = this.el_.style[widthOrHeight];
+    var pxIndex = val.indexOf('px');
 
-    this.emitTapEvents();
+    if (pxIndex !== -1) {
+      // Return the pixel value with no 'px'
+      return parseInt(val.slice(0, pxIndex), 10);
+    }
 
-    this.on('tap', this.handleClick);
-    this.on('click', this.handleClick);
-    this.on('focus', this.handleFocus);
-    this.on('blur', this.handleBlur);
-  }
+    // No px so using % or no style was set, so falling back to offsetWidth/height
+    // If component has display:none, offset will return 0
+    // TODO: handle display:none and no dimension style using px
+    return parseInt(this.el_['offset' + (0, _toTitleCase2['default'])(widthOrHeight)], 10);
+  };
 
   /**
-   * Create the component's DOM element
-   *
-   * @param {String=} type Element's node type. e.g. 'div'
-   * @param {Object=} props An object of properties that should be set on the element
-   * @param {Object=} attributes An object of attributes that should be set on the element
-   * @return {Element}
-   * @method createEl
+   * Get width or height of computed style
+   * @param  {String} widthOrHeight  'width' or 'height'
+   * @return {Number|Boolean} The bolean false if nothing was set
+   * @method currentDimension
    */
 
-  ClickableComponent.prototype.createEl = function createEl() {
-    var tag = arguments.length <= 0 || arguments[0] === undefined ? 'div' : arguments[0];
-    var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-    var attributes = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
 
-    props = _objectAssign2['default']({
-      className: this.buildCSSClass(),
-      tabIndex: 0
-    }, props);
+  Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
+    var computedWidthOrHeight = 0;
 
-    if (tag === 'button') {
-      _utilsLogJs2['default'].error('Creating a ClickableComponent with an HTML element of ' + tag + ' is not supported; use a Button instead.');
+    if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
+      throw new Error('currentDimension only accepts width or height value');
     }
 
-    // Add ARIA attributes for clickable element which is not a native HTML button
-    attributes = _objectAssign2['default']({
-      role: 'button',
-      'aria-live': 'polite' // let the screen reader user know that the text of the element may change
-    }, attributes);
+    if (typeof _window2['default'].getComputedStyle === 'function') {
+      var computedStyle = _window2['default'].getComputedStyle(this.el_);
 
-    var el = _Component.prototype.createEl.call(this, tag, props, attributes);
+      computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
+    } else if (this.el_.currentStyle) {
+      // ie 8 doesn't support computed style, shim it
+      // return clientWidth or clientHeight instead for better accuracy
+      var rule = 'offset' + (0, _toTitleCase2['default'])(widthOrHeight);
 
-    this.createControlTextEl(el);
+      computedWidthOrHeight = this.el_[rule];
+    }
 
-    return el;
+    // remove 'px' from variable and parse as integer
+    computedWidthOrHeight = parseFloat(computedWidthOrHeight);
+    return computedWidthOrHeight;
   };
 
   /**
-   * create control text
-   *
-   * @param {Element} el Parent element for the control text
-   * @return {Element}
-   * @method controlText
+   * Get an object which contains width and height values of computed style
+   * @return {Object} The dimensions of element
+   * @method currentDimensions
    */
 
-  ClickableComponent.prototype.createControlTextEl = function createControlTextEl(el) {
-    this.controlTextEl_ = Dom.createEl('span', {
-      className: 'vjs-control-text'
-    });
-
-    if (el) {
-      el.appendChild(this.controlTextEl_);
-    }
-
-    this.controlText(this.controlText_, el);
 
-    return this.controlTextEl_;
+  Component.prototype.currentDimensions = function currentDimensions() {
+    return {
+      width: this.currentDimension('width'),
+      height: this.currentDimension('height')
+    };
   };
 
   /**
-   * Controls text - both request and localize
-   *
-   * @param {String}  text Text for element
-   * @param {Element=} el Element to set the title on
-   * @return {String}
-   * @method controlText
+   * Get width of computed style
+   * @return {Integer}
+   * @method currentWidth
    */
 
-  ClickableComponent.prototype.controlText = function controlText(text) {
-    var el = arguments.length <= 1 || arguments[1] === undefined ? this.el() : arguments[1];
-
-    if (!text) return this.controlText_ || 'Need Text';
-
-    var localizedText = this.localize(text);
-
-    this.controlText_ = text;
-    this.controlTextEl_.innerHTML = localizedText;
-    el.setAttribute('title', localizedText);
 
-    return this;
+  Component.prototype.currentWidth = function currentWidth() {
+    return this.currentDimension('width');
   };
 
   /**
-   * Allows sub components to stack CSS class names
-   *
-   * @return {String}
-   * @method buildCSSClass
+   * Get height of computed style
+   * @return {Integer}
+   * @method currentHeight
    */
 
-  ClickableComponent.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-control vjs-button ' + _Component.prototype.buildCSSClass.call(this);
+
+  Component.prototype.currentHeight = function currentHeight() {
+    return this.currentDimension('height');
   };
 
   /**
-   * Adds a child component inside this clickable-component
+   * Emit 'tap' events when touch events are supported
+   * This is used to support toggling the controls through a tap on the video.
+   * We're requiring them to be enabled because otherwise every component would
+   * have this extra overhead unnecessarily, on mobile devices where extra
+   * overhead is especially bad.
    *
-   * @param {String|Component} child The class name or instance of a child to add
-   * @param {Object=} options Options, including options to be passed to children of the child.
-   * @return {Component} The child component (created by this process if a string was used)
-   * @method addChild
+   * @private
+   * @method emitTapEvents
    */
 
-  ClickableComponent.prototype.addChild = function addChild(child) {
-    var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
 
-    // TODO: Fix adding an actionable child to a ClickableComponent; currently
-    // it will cause issues with assistive technology (e.g. screen readers)
-    // which support ARIA, since an element with role="button" cannot have
-    // actionable child elements.
+  Component.prototype.emitTapEvents = function emitTapEvents() {
+    // Track the start time so we can determine how long the touch lasted
+    var touchStart = 0;
+    var firstTouch = null;
 
-    //let className = this.constructor.name;
-    //log.warn(`Adding a child to a ClickableComponent (${className}) can cause issues with assistive technology which supports ARIA, since an element with role="button" cannot have actionable child elements.`);
+    // Maximum movement allowed during a touch event to still be considered a tap
+    // Other popular libs use anywhere from 2 (hammer.js) to 15, so 10 seems like a nice, round number.
+    var tapMovementThreshold = 10;
 
-    return _Component.prototype.addChild.call(this, child, options);
-  };
+    // The maximum length a touch can be while still being considered a tap
+    var touchTimeThreshold = 200;
 
-  /**
-   * Enable the component element
-   *
-   * @return {Component}
-   * @method enable
-   */
+    var couldBeTap = void 0;
 
-  ClickableComponent.prototype.enable = function enable() {
-    this.removeClass('vjs-disabled');
-    this.el_.setAttribute('aria-disabled', 'false');
-    return this;
-  };
+    this.on('touchstart', function (event) {
+      // If more than one finger, don't consider treating this as a click
+      if (event.touches.length === 1) {
+        // Copy pageX/pageY from the object
+        firstTouch = {
+          pageX: event.touches[0].pageX,
+          pageY: event.touches[0].pageY
+        };
+        // Record start time so we can detect a tap vs. "touch and hold"
+        touchStart = new Date().getTime();
+        // Reset couldBeTap tracking
+        couldBeTap = true;
+      }
+    });
 
-  /**
-   * Disable the component element
-   *
-   * @return {Component}
-   * @method disable
-   */
+    this.on('touchmove', function (event) {
+      // If more than one finger, don't consider treating this as a click
+      if (event.touches.length > 1) {
+        couldBeTap = false;
+      } else if (firstTouch) {
+        // Some devices will throw touchmoves for all but the slightest of taps.
+        // So, if we moved only a small distance, this could still be a tap
+        var xdiff = event.touches[0].pageX - firstTouch.pageX;
+        var ydiff = event.touches[0].pageY - firstTouch.pageY;
+        var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
 
-  ClickableComponent.prototype.disable = function disable() {
-    this.addClass('vjs-disabled');
-    this.el_.setAttribute('aria-disabled', 'true');
-    return this;
-  };
+        if (touchDistance > tapMovementThreshold) {
+          couldBeTap = false;
+        }
+      }
+    });
 
-  /**
-   * Handle Click - Override with specific functionality for component
-   *
-   * @method handleClick
-   */
+    var noTap = function noTap() {
+      couldBeTap = false;
+    };
 
-  ClickableComponent.prototype.handleClick = function handleClick() {};
+    // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
+    this.on('touchleave', noTap);
+    this.on('touchcancel', noTap);
 
-  /**
-   * Handle Focus - Add keyboard functionality to element
-   *
-   * @method handleFocus
-   */
+    // When the touch ends, measure how long it took and trigger the appropriate
+    // event
+    this.on('touchend', function (event) {
+      firstTouch = null;
+      // Proceed only if the touchmove/leave/cancel event didn't happen
+      if (couldBeTap === true) {
+        // Measure how long the touch lasted
+        var touchTime = new Date().getTime() - touchStart;
 
-  ClickableComponent.prototype.handleFocus = function handleFocus() {
-    Events.on(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
+        // Make sure the touch was less than the threshold to be considered a tap
+        if (touchTime < touchTimeThreshold) {
+          // Don't let browser turn this into a click
+          event.preventDefault();
+          this.trigger('tap');
+          // It may be good to copy the touchend event object and change the
+          // type to tap, if the other event properties aren't exact after
+          // Events.fixEvent runs (e.g. event.target)
+        }
+      }
+    });
   };
 
   /**
-   * Handle KeyPress (document level) - Trigger click when Space or Enter key is pressed
+   * Report user touch activity when touch events occur
+   * User activity is used to determine when controls should show/hide. It's
+   * relatively simple when it comes to mouse events, because any mouse event
+   * should show the controls. So we capture mouse events that bubble up to the
+   * player and report activity when that happens.
+   * With touch events it isn't as easy. We can't rely on touch events at the
+   * player level, because a tap (touchstart + touchend) on the video itself on
+   * mobile devices is meant to turn controls off (and on). User activity is
+   * checked asynchronously, so what could happen is a tap event on the video
+   * turns the controls off, then the touchend event bubbles up to the player,
+   * which if it reported user activity, would turn the controls right back on.
+   * (We also don't want to completely block touch events from bubbling up)
+   * Also a touchmove, touch+hold, and anything other than a tap is not supposed
+   * to turn the controls back on on a mobile device.
+   * Here we're setting the default component behavior to report user activity
+   * whenever touch events happen, and this can be turned off by components that
+   * want touch events to act differently.
    *
-   * @method handleKeyPress
+   * @method enableTouchActivity
    */
 
-  ClickableComponent.prototype.handleKeyPress = function handleKeyPress(event) {
-    // Support Space (32) or Enter (13) key operation to fire a click event
-    if (event.which === 32 || event.which === 13) {
-      event.preventDefault();
-      this.handleClick(event);
-    } else if (_Component.prototype.handleKeyPress) {
-      _Component.prototype.handleKeyPress.call(this, event); // Pass keypress handling up for unsupported keys
+
+  Component.prototype.enableTouchActivity = function enableTouchActivity() {
+    // Don't continue if the root player doesn't support reporting user activity
+    if (!this.player() || !this.player().reportUserActivity) {
+      return;
     }
+
+    // listener for reporting that the user is active
+    var report = Fn.bind(this.player(), this.player().reportUserActivity);
+
+    var touchHolding = void 0;
+
+    this.on('touchstart', function () {
+      report();
+      // For as long as the they are touching the device or have their mouse down,
+      // we consider them active even if they're not moving their finger or mouse.
+      // So we want to continue to update that they are active
+      this.clearInterval(touchHolding);
+      // report at the same interval as activityCheck
+      touchHolding = this.setInterval(report, 250);
+    });
+
+    var touchEnd = function touchEnd(event) {
+      report();
+      // stop the interval that maintains activity if the touch is holding
+      this.clearInterval(touchHolding);
+    };
+
+    this.on('touchmove', report);
+    this.on('touchend', touchEnd);
+    this.on('touchcancel', touchEnd);
   };
 
   /**
-   * Handle Blur - Remove keyboard triggers
+   * Creates timeout and sets up disposal automatically.
    *
-   * @method handleBlur
+   * @param {Function} fn The function to run after the timeout.
+   * @param {Number} timeout Number of ms to delay before executing specified function.
+   * @return {Number} Returns the timeout ID
+   * @method setTimeout
    */
 
-  ClickableComponent.prototype.handleBlur = function handleBlur() {
-    Events.off(_globalDocument2['default'], 'keydown', Fn.bind(this, this.handleKeyPress));
-  };
 
-  return ClickableComponent;
-})(_component2['default']);
+  Component.prototype.setTimeout = function setTimeout(fn, timeout) {
+    fn = Fn.bind(this, fn);
 
-_component2['default'].registerComponent('ClickableComponent', ClickableComponent);
-exports['default'] = ClickableComponent;
-module.exports = exports['default'];
+    // window.setTimeout would be preferable here, but due to some bizarre issue with Sinon and/or Phantomjs, we can't.
+    var timeoutId = _window2['default'].setTimeout(fn, timeout);
 
-},{"./component":67,"./utils/dom.js":142,"./utils/events.js":143,"./utils/fn.js":144,"./utils/log.js":147,"global/document":1,"object.assign":45}],66:[function(_dereq_,module,exports){
-'use strict';
+    var disposeFn = function disposeFn() {
+      this.clearTimeout(timeoutId);
+    };
 
-exports.__esModule = true;
+    disposeFn.guid = 'vjs-timeout-' + timeoutId;
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+    this.on('dispose', disposeFn);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+    return timeoutId;
+  };
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+  /**
+   * Clears a timeout and removes the associated dispose listener
+   *
+   * @param {Number} timeoutId The id of the timeout to clear
+   * @return {Number} Returns the timeout ID
+   * @method clearTimeout
+   */
 
-var _button = _dereq_('./button');
 
-var _button2 = _interopRequireDefault(_button);
+  Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
+    _window2['default'].clearTimeout(timeoutId);
 
-var _component = _dereq_('./component');
+    var disposeFn = function disposeFn() {};
 
-var _component2 = _interopRequireDefault(_component);
+    disposeFn.guid = 'vjs-timeout-' + timeoutId;
 
-/**
- * The `CloseButton` component is a button which fires a "close" event
- * when it is activated.
- *
- * @extends Button
- * @class CloseButton
- */
+    this.off('dispose', disposeFn);
 
-var CloseButton = (function (_Button) {
-  _inherits(CloseButton, _Button);
+    return timeoutId;
+  };
 
-  function CloseButton(player, options) {
-    _classCallCheck(this, CloseButton);
+  /**
+   * Creates an interval and sets up disposal automatically.
+   *
+   * @param {Function} fn The function to run every N seconds.
+   * @param {Number} interval Number of ms to delay before executing specified function.
+   * @return {Number} Returns the interval ID
+   * @method setInterval
+   */
 
-    _Button.call(this, player, options);
-    this.controlText(options && options.controlText || this.localize('Close'));
-  }
 
-  CloseButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-close-button ' + _Button.prototype.buildCSSClass.call(this);
-  };
+  Component.prototype.setInterval = function setInterval(fn, interval) {
+    fn = Fn.bind(this, fn);
 
-  CloseButton.prototype.handleClick = function handleClick() {
-    this.trigger({ type: 'close', bubbles: false });
-  };
+    var intervalId = _window2['default'].setInterval(fn, interval);
 
-  return CloseButton;
-})(_button2['default']);
+    var disposeFn = function disposeFn() {
+      this.clearInterval(intervalId);
+    };
 
-_component2['default'].registerComponent('CloseButton', CloseButton);
-exports['default'] = CloseButton;
-module.exports = exports['default'];
+    disposeFn.guid = 'vjs-interval-' + intervalId;
 
-},{"./button":64,"./component":67}],67:[function(_dereq_,module,exports){
-/**
- * @file component.js
- *
- * Player Component - Base class for all UI objects
- */
+    this.on('dispose', disposeFn);
 
-'use strict';
+    return intervalId;
+  };
 
-exports.__esModule = true;
+  /**
+   * Clears an interval and removes the associated dispose listener
+   *
+   * @param {Number} intervalId The id of the interval to clear
+   * @return {Number} Returns the interval ID
+   * @method clearInterval
+   */
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+  Component.prototype.clearInterval = function clearInterval(intervalId) {
+    _window2['default'].clearInterval(intervalId);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+    var disposeFn = function disposeFn() {};
 
-var _globalWindow = _dereq_('global/window');
+    disposeFn.guid = 'vjs-interval-' + intervalId;
 
-var _globalWindow2 = _interopRequireDefault(_globalWindow);
+    this.off('dispose', disposeFn);
 
-var _utilsDomJs = _dereq_('./utils/dom.js');
+    return intervalId;
+  };
 
-var Dom = _interopRequireWildcard(_utilsDomJs);
+  /**
+   * Registers a component
+   *
+   * @param {String} name Name of the component to register
+   * @param {Object} comp The component to register
+   * @static
+   * @method registerComponent
+   */
 
-var _utilsFnJs = _dereq_('./utils/fn.js');
 
-var Fn = _interopRequireWildcard(_utilsFnJs);
+  Component.registerComponent = function registerComponent(name, comp) {
+    if (!Component.components_) {
+      Component.components_ = {};
+    }
 
-var _utilsGuidJs = _dereq_('./utils/guid.js');
+    Component.components_[name] = comp;
+    return comp;
+  };
 
-var Guid = _interopRequireWildcard(_utilsGuidJs);
+  /**
+   * Gets a component by name
+   *
+   * @param {String} name Name of the component to get
+   * @return {Component}
+   * @static
+   * @method getComponent
+   */
 
-var _utilsEventsJs = _dereq_('./utils/events.js');
 
-var Events = _interopRequireWildcard(_utilsEventsJs);
+  Component.getComponent = function getComponent(name) {
+    if (Component.components_ && Component.components_[name]) {
+      return Component.components_[name];
+    }
 
-var _utilsLogJs = _dereq_('./utils/log.js');
+    if (_window2['default'] && _window2['default'].videojs && _window2['default'].videojs[name]) {
+      _log2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)');
+      return _window2['default'].videojs[name];
+    }
+  };
 
-var _utilsLogJs2 = _interopRequireDefault(_utilsLogJs);
+  /**
+   * Sets up the constructor using the supplied init method
+   * or uses the init of the parent object
+   *
+   * @param {Object} props An object of properties
+   * @static
+   * @deprecated
+   * @method extend
+   */
 
-var _utilsToTitleCaseJs = _dereq_('./utils/to-title-case.js');
 
-var _utilsToTitleCaseJs2 = _interopRequireDefault(_utilsToTitleCaseJs);
+  Component.extend = function extend(props) {
+    props = props || {};
 
-var _utilsMergeOptionsJs = _dereq_('./utils/merge-options.js');
+    _log2['default'].warn('Component.extend({}) has been deprecated, use videojs.extend(Component, {}) instead');
 
-var _utilsMergeOptionsJs2 = _interopRequireDefault(_utilsMergeOptionsJs);
+    // Set up the constructor using the supplied init method
+    // or using the init of the parent object
+    // Make sure to check the unobfuscated version for external libs
+    var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {};
+    // In Resig's simple class inheritance (previously used) the constructor
+    //  is a function that calls `this.init.apply(arguments)`
+    // However that would prevent us from using `ParentObject.call(this);`
+    //  in a Child constructor because the `this` in `this.init`
+    //  would still refer to the Child and cause an infinite loop.
+    // We would instead have to do
+    //    `ParentObject.prototype.init.apply(this, arguments);`
+    //  Bleh. We're not creating a _super() function, so it's good to keep
+    //  the parent constructor reference simple.
+    var subObj = function subObj() {
+      init.apply(this, arguments);
+    };
 
-/**
- * Base UI Component class
- * Components are embeddable UI objects that are represented by both a
- * javascript object and an element in the DOM. They can be children of other
- * components, and can have many children themselves.
- * ```js
- *     // adding a button to the player
- *     var button = player.addChild('button');
- *     button.el(); // -> button element
- * ```
- * ```html
- *     <div class="video-js">
- *       <div class="vjs-button">Button</div>
- *     </div>
- * ```
- * Components are also event targets.
- * ```js
- *     button.on('click', function(){
- *       console.log('Button Clicked!');
- *     });
- *     button.trigger('customevent');
- * ```
- *
- * @param {Object} player  Main Player
- * @param {Object=} options Object of option names and values
- * @param {Function=} ready    Ready callback function
- * @class Component
- */
+    // Inherit from this object's prototype
+    subObj.prototype = Object.create(this.prototype);
+    // Reset the constructor property for subObj otherwise
+    // instances of subObj would have the constructor of the parent Object
+    subObj.prototype.constructor = subObj;
 
-var Component = (function () {
-  function Component(player, options, ready) {
-    _classCallCheck(this, Component);
+    // Make the class extendable
+    subObj.extend = Component.extend;
 
-    // The component might be the player itself and we can't pass `this` to super
-    if (!player && this.play) {
-      this.player_ = player = this; // eslint-disable-line
-    } else {
-        this.player_ = player;
+    // Extend subObj's prototype with functions and other properties from props
+    for (var name in props) {
+      if (props.hasOwnProperty(name)) {
+        subObj.prototype[name] = props[name];
       }
+    }
 
-    // Make a copy of prototype.options_ to protect against overriding defaults
-    this.options_ = _utilsMergeOptionsJs2['default']({}, this.options_);
-
-    // Updated options with supplied options
-    options = this.options_ = _utilsMergeOptionsJs2['default'](this.options_, options);
-
-    // Get ID from options or options element if one is supplied
-    this.id_ = options.id || options.el && options.el.id;
+    return subObj;
+  };
 
-    // If there was no ID from the options, generate one
-    if (!this.id_) {
-      // Don't require the player ID function in the case of mock players
-      var id = player && player.id && player.id() || 'no_player';
+  return Component;
+}();
 
-      this.id_ = id + '_component_' + Guid.newGUID();
-    }
+Component.registerComponent('Component', Component);
+exports['default'] = Component;
 
-    this.name_ = options.name || null;
+},{"80":80,"81":81,"82":82,"84":84,"85":85,"86":86,"89":89,"93":93}],6:[function(_dereq_,module,exports){
+'use strict';
 
-    // Create element if one wasn't provided in options
-    if (options.el) {
-      this.el_ = options.el;
-    } else if (options.createEl !== false) {
-      this.el_ = this.createEl();
-    }
+exports.__esModule = true;
 
-    this.children_ = [];
-    this.childIndex_ = {};
-    this.childNameIndex_ = {};
+var _trackButton = _dereq_(36);
 
-    // Add any child components in options
-    if (options.initChildren !== false) {
-      this.initChildren();
-    }
+var _trackButton2 = _interopRequireDefault(_trackButton);
 
-    this.ready(ready);
-    // Don't want to trigger ready here or it will before init is actually
-    // finished for all children that run this constructor
+var _component = _dereq_(5);
 
-    if (options.reportTouchActivity !== false) {
-      this.enableTouchActivity();
-    }
-  }
+var _component2 = _interopRequireDefault(_component);
 
-  /**
-   * Dispose of the component and all child components
-   *
-   * @method dispose
-   */
+var _audioTrackMenuItem = _dereq_(7);
 
-  Component.prototype.dispose = function dispose() {
-    this.trigger({ type: 'dispose', bubbles: false });
+var _audioTrackMenuItem2 = _interopRequireDefault(_audioTrackMenuItem);
 
-    // Dispose all children.
-    if (this.children_) {
-      for (var i = this.children_.length - 1; i >= 0; i--) {
-        if (this.children_[i].dispose) {
-          this.children_[i].dispose();
-        }
-      }
-    }
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-    // Delete child references
-    this.children_ = null;
-    this.childIndex_ = null;
-    this.childNameIndex_ = null;
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-    // Remove all event listeners.
-    this.off();
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-    // Remove element from DOM
-    if (this.el_.parentNode) {
-      this.el_.parentNode.removeChild(this.el_);
-    }
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-button.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-    Dom.removeElData(this.el_);
-    this.el_ = null;
-  };
 
-  /**
-   * Return the component's player
-   *
-   * @return {Player}
-   * @method player
-   */
+/**
+ * The base class for buttons that toggle specific text track types (e.g. subtitles)
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends TrackButton
+ * @class AudioTrackButton
+ */
+var AudioTrackButton = function (_TrackButton) {
+  _inherits(AudioTrackButton, _TrackButton);
 
-  Component.prototype.player = function player() {
-    return this.player_;
-  };
+  function AudioTrackButton(player) {
+    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 
-  /**
-   * Deep merge of options objects
-   * Whenever a property is an object on both options objects
-   * the two properties will be merged using mergeOptions.
-   *
-   * ```js
-   *     Parent.prototype.options_ = {
-   *       optionSet: {
-   *         'childOne': { 'foo': 'bar', 'asdf': 'fdsa' },
-   *         'childTwo': {},
-   *         'childThree': {}
-   *       }
-   *     }
-   *     newOptions = {
-   *       optionSet: {
-   *         'childOne': { 'foo': 'baz', 'abc': '123' }
-   *         'childTwo': null,
-   *         'childFour': {}
-   *       }
-   *     }
-   *
-   *     this.options(newOptions);
-   * ```
-   * RESULT
-   * ```js
-   *     {
-   *       optionSet: {
-   *         'childOne': { 'foo': 'baz', 'asdf': 'fdsa', 'abc': '123' },
-   *         'childTwo': null, // Disabled. Won't be initialized.
-   *         'childThree': {},
-   *         'childFour': {}
-   *       }
-   *     }
-   * ```
-   *
-   * @param  {Object} obj Object of new option values
-   * @return {Object}     A NEW object of this.options_ and obj merged
-   * @method options
-   */
+    _classCallCheck(this, AudioTrackButton);
 
-  Component.prototype.options = function options(obj) {
-    _utilsLogJs2['default'].warn('this.options() has been deprecated and will be moved to the constructor in 6.0');
+    options.tracks = player.audioTracks && player.audioTracks();
 
-    if (!obj) {
-      return this.options_;
-    }
+    var _this = _possibleConstructorReturn(this, _TrackButton.call(this, player, options));
 
-    this.options_ = _utilsMergeOptionsJs2['default'](this.options_, obj);
-    return this.options_;
-  };
+    _this.el_.setAttribute('aria-label', 'Audio Menu');
+    return _this;
+  }
 
   /**
-   * Get the component's DOM element
-   * ```js
-   *     var domEl = myComponent.el();
-   * ```
+   * Allow sub components to stack CSS class names
    *
-   * @return {Element}
-   * @method el
+   * @return {String} The constructed class name
+   * @method buildCSSClass
    */
 
-  Component.prototype.el = function el() {
-    return this.el_;
+
+  AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Create the component's DOM element
+   * Create a menu item for each audio track
    *
-   * @param  {String=} tagName  Element's node type. e.g. 'div'
-   * @param  {Object=} properties An object of properties that should be set
-   * @param  {Object=} attributes An object of attributes that should be set
-   * @return {Element}
-   * @method createEl
+   * @return {Array} Array of menu items
+   * @method createItems
    */
 
-  Component.prototype.createEl = function createEl(tagName, properties, attributes) {
-    return Dom.createEl(tagName, properties, attributes);
-  };
-
-  Component.prototype.localize = function localize(string) {
-    var code = this.player_.language && this.player_.language();
-    var languages = this.player_.languages && this.player_.languages();
 
-    if (!code || !languages) {
-      return string;
-    }
+  AudioTrackButton.prototype.createItems = function createItems() {
+    var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
 
-    var language = languages[code];
+    var tracks = this.player_.audioTracks && this.player_.audioTracks();
 
-    if (language && language[string]) {
-      return language[string];
+    if (!tracks) {
+      return items;
     }
 
-    var primaryCode = code.split('-')[0];
-    var primaryLang = languages[primaryCode];
+    for (var i = 0; i < tracks.length; i++) {
+      var track = tracks[i];
 
-    if (primaryLang && primaryLang[string]) {
-      return primaryLang[string];
+      items.push(new _audioTrackMenuItem2['default'](this.player_, {
+        track: track,
+        // MenuItem is selectable
+        selectable: true
+      }));
     }
 
-    return string;
+    return items;
   };
 
-  /**
-   * Return the component's DOM element where children are inserted.
-   * Will either be the same as el() or a new element defined in createEl().
-   *
-   * @return {Element}
-   * @method contentEl
-   */
+  return AudioTrackButton;
+}(_trackButton2['default']);
 
-  Component.prototype.contentEl = function contentEl() {
-    return this.contentEl_ || this.el_;
-  };
+AudioTrackButton.prototype.controlText_ = 'Audio Track';
+_component2['default'].registerComponent('AudioTrackButton', AudioTrackButton);
+exports['default'] = AudioTrackButton;
 
-  /**
-   * Get the component's ID
-   * ```js
-   *     var id = myComponent.id();
-   * ```
-   *
-   * @return {String}
-   * @method id
-   */
+},{"36":36,"5":5,"7":7}],7:[function(_dereq_,module,exports){
+'use strict';
 
-  Component.prototype.id = function id() {
-    return this.id_;
-  };
+exports.__esModule = true;
 
-  /**
-   * Get the component's name. The name is often used to reference the component.
-   * ```js
-   *     var name = myComponent.name();
-   * ```
-   *
-   * @return {String}
-   * @method name
-   */
+var _menuItem = _dereq_(48);
 
-  Component.prototype.name = function name() {
-    return this.name_;
-  };
+var _menuItem2 = _interopRequireDefault(_menuItem);
 
-  /**
-   * Get an array of all child components
-   * ```js
-   *     var kids = myComponent.children();
-   * ```
-   *
-   * @return {Array} The children
-   * @method children
-   */
+var _component = _dereq_(5);
 
-  Component.prototype.children = function children() {
-    return this.children_;
-  };
+var _component2 = _interopRequireDefault(_component);
+
+var _fn = _dereq_(82);
+
+var Fn = _interopRequireWildcard(_fn);
+
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file audio-track-menu-item.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+
+/**
+ * The audio track menu item
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends MenuItem
+ * @class AudioTrackMenuItem
+ */
+var AudioTrackMenuItem = function (_MenuItem) {
+  _inherits(AudioTrackMenuItem, _MenuItem);
+
+  function AudioTrackMenuItem(player, options) {
+    _classCallCheck(this, AudioTrackMenuItem);
+
+    var track = options.track;
+    var tracks = player.audioTracks();
+
+    // Modify options for parent MenuItem class's init.
+    options.label = track.label || track.language || 'Unknown';
+    options.selected = track.enabled;
+
+    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
+
+    _this.track = track;
+
+    if (tracks) {
+      (function () {
+        var changeHandler = Fn.bind(_this, _this.handleTracksChange);
+
+        tracks.addEventListener('change', changeHandler);
+        _this.on('dispose', function () {
+          tracks.removeEventListener('change', changeHandler);
+        });
+      })();
+    }
+    return _this;
+  }
 
   /**
-   * Returns a child component with the provided ID
+   * Handle click on audio track
    *
-   * @return {Component}
-   * @method getChildById
+   * @method handleClick
    */
 
-  Component.prototype.getChildById = function getChildById(id) {
-    return this.childIndex_[id];
+
+  AudioTrackMenuItem.prototype.handleClick = function handleClick(event) {
+    var tracks = this.player_.audioTracks();
+
+    _MenuItem.prototype.handleClick.call(this, event);
+
+    if (!tracks) {
+      return;
+    }
+
+    for (var i = 0; i < tracks.length; i++) {
+      var track = tracks[i];
+
+      track.enabled = track === this.track;
+    }
   };
 
   /**
-   * Returns a child component with the provided name
+   * Handle audio track change
    *
-   * @return {Component}
-   * @method getChild
+   * @method handleTracksChange
    */
 
-  Component.prototype.getChild = function getChild(name) {
-    return this.childNameIndex_[name];
+
+  AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
+    this.selected(this.track.enabled);
   };
 
-  /**
-   * Adds a child component inside this component
-   * ```js
-   *     myComponent.el();
-   *     // -> <div class='my-component'></div>
-   *     myComponent.children();
-   *     // [empty array]
-   *
-   *     var myButton = myComponent.addChild('MyButton');
-   *     // -> <div class='my-component'><div class="my-button">myButton<div></div>
-   *     // -> myButton === myComponent.children()[0];
-   * ```
-   * Pass in options for child constructors and options for children of the child
-   * ```js
-   *     var myButton = myComponent.addChild('MyButton', {
-   *       text: 'Press Me',
-   *       buttonChildExample: {
-   *         buttonChildOption: true
-   *       }
-   *     });
-   * ```
-   *
-   * @param {String|Component} child The class name or instance of a child to add
-   * @param {Object=} options Options, including options to be passed to children of the child.
-   * @param {Number} index into our children array to attempt to add the child
-   * @return {Component} The child component (created by this process if a string was used)
-   * @method addChild
-   */
+  return AudioTrackMenuItem;
+}(_menuItem2['default']);
 
-  Component.prototype.addChild = function addChild(child) {
-    var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
-    var index = arguments.length <= 2 || arguments[2] === undefined ? this.children_.length : arguments[2];
+_component2['default'].registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);
+exports['default'] = AudioTrackMenuItem;
 
-    var component = undefined;
-    var componentName = undefined;
+},{"48":48,"5":5,"82":82}],8:[function(_dereq_,module,exports){
+'use strict';
 
-    // If child is a string, create nt with options
-    if (typeof child === 'string') {
-      componentName = child;
+exports.__esModule = true;
 
-      // Options can also be specified as a boolean, so convert to an empty object if false.
-      if (!options) {
-        options = {};
-      }
+var _component = _dereq_(5);
 
-      // Same as above, but true is deprecated so show a warning.
-      if (options === true) {
-        _utilsLogJs2['default'].warn('Initializing a child component with `true` is deprecated. Children should be defined in an array when possible, but if necessary use an object instead of `true`.');
-        options = {};
-      }
+var _component2 = _interopRequireDefault(_component);
 
-      // If no componentClass in options, assume componentClass is the name lowercased
-      // (e.g. playButton)
-      var componentClassName = options.componentClass || _utilsToTitleCaseJs2['default'](componentName);
+_dereq_(12);
 
-      // Set name through options
-      options.name = componentName;
+_dereq_(32);
 
-      // Create a new object & element for this controls set
-      // If there's no .player_, this is a player
-      var ComponentClass = Component.getComponent(componentClassName);
+_dereq_(33);
 
-      if (!ComponentClass) {
-        throw new Error('Component ' + componentClassName + ' does not exist');
-      }
+_dereq_(35);
 
-      // data stored directly on the videojs object may be
-      // misidentified as a component to retain
-      // backwards-compatibility with 4.x. check to make sure the
-      // component class can be instantiated.
-      if (typeof ComponentClass !== 'function') {
-        return null;
-      }
+_dereq_(34);
 
-      component = new ComponentClass(this.player_ || this, options);
+_dereq_(10);
 
-      // child is a component instance
-    } else {
-        component = child;
-      }
+_dereq_(18);
 
-    this.children_.splice(index, 0, component);
+_dereq_(9);
 
-    if (typeof component.id === 'function') {
-      this.childIndex_[component.id()] = component;
-    }
+_dereq_(38);
 
-    // If a name wasn't used to create the component, check if we can use the
-    // name function of the component
-    componentName = componentName || component.name && component.name();
+_dereq_(40);
 
-    if (componentName) {
-      this.childNameIndex_[componentName] = component;
-    }
+_dereq_(11);
 
-    // Add the UI object's element to the container div (box)
-    // Having an element is not required
-    if (typeof component.el === 'function' && component.el()) {
-      var childNodes = this.contentEl().children;
-      var refNode = childNodes[index] || null;
-      this.contentEl().insertBefore(component.el(), refNode);
-    }
+_dereq_(25);
 
-    // Return so it can stored on parent object if desired.
-    return component;
-  };
+_dereq_(27);
 
-  /**
-   * Remove a child component from this component's list of children, and the
-   * child component's element from this component's element
-   *
-   * @param  {Component} component Component to remove
-   * @method removeChild
-   */
+_dereq_(29);
 
-  Component.prototype.removeChild = function removeChild(component) {
-    if (typeof component === 'string') {
-      component = this.getChild(component);
-    }
+_dereq_(24);
 
-    if (!component || !this.children_) {
-      return;
-    }
+_dereq_(6);
 
-    var childFound = false;
+_dereq_(13);
 
-    for (var i = this.children_.length - 1; i >= 0; i--) {
-      if (this.children_[i] === component) {
-        childFound = true;
-        this.children_.splice(i, 1);
-        break;
-      }
-    }
+_dereq_(21);
 
-    if (!childFound) {
-      return;
-    }
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-    this.childIndex_[component.id()] = null;
-    this.childNameIndex_[component.name()] = null;
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-    var compEl = component.el();
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-    if (compEl && compEl.parentNode === this.contentEl()) {
-      this.contentEl().removeChild(component.el());
-    }
-  };
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file control-bar.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+
+// Required children
+
+
+/**
+ * Container of main controls
+ *
+ * @extends Component
+ * @class ControlBar
+ */
+var ControlBar = function (_Component) {
+  _inherits(ControlBar, _Component);
+
+  function ControlBar() {
+    _classCallCheck(this, ControlBar);
+
+    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
+  }
 
   /**
-   * Add and initialize default child components from options
-   * ```js
-   *     // when an instance of MyComponent is created, all children in options
-   *     // will be added to the instance by their name strings and options
-   *     MyComponent.prototype.options_ = {
-   *       children: [
-   *         'myChildComponent'
-   *       ],
-   *       myChildComponent: {
-   *         myChildOption: true
-   *       }
-   *     };
+   * Create the component's DOM element
    *
-   *     // Or when creating the component
-   *     var myComp = new MyComponent(player, {
-   *       children: [
-   *         'myChildComponent'
-   *       ],
-   *       myChildComponent: {
-   *         myChildOption: true
-   *       }
-   *     });
-   * ```
-   * The children option can also be an array of
-   * child options objects (that also include a 'name' key).
-   * This can be used if you have two child components of the
-   * same type that need different options.
-   * ```js
-   *     var myComp = new MyComponent(player, {
-   *       children: [
-   *         'button',
-   *         {
-   *           name: 'button',
-   *           someOtherOption: true
-   *         },
-   *         {
-   *           name: 'button',
-   *           someOtherOption: false
-   *         }
-   *       ]
-   *     });
-   * ```
-   *
-   * @method initChildren
+   * @return {Element}
+   * @method createEl
    */
+  ControlBar.prototype.createEl = function createEl() {
+    return _Component.prototype.createEl.call(this, 'div', {
+      className: 'vjs-control-bar',
+      dir: 'ltr'
+    }, {
+      // The control bar is a group, so it can contain menuitems
+      role: 'group'
+    });
+  };
 
-  Component.prototype.initChildren = function initChildren() {
-    var _this = this;
+  return ControlBar;
+}(_component2['default']);
 
-    var children = this.options_.children;
+ControlBar.prototype.options_ = {
+  children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'audioTrackButton', 'fullscreenToggle']
+};
 
-    if (children) {
-      (function () {
-        // `this` is `parent`
-        var parentOptions = _this.options_;
+_component2['default'].registerComponent('ControlBar', ControlBar);
+exports['default'] = ControlBar;
 
-        var handleAdd = function handleAdd(child) {
-          var name = child.name;
-          var opts = child.opts;
+},{"10":10,"11":11,"12":12,"13":13,"18":18,"21":21,"24":24,"25":25,"27":27,"29":29,"32":32,"33":33,"34":34,"35":35,"38":38,"40":40,"5":5,"6":6,"9":9}],9:[function(_dereq_,module,exports){
+'use strict';
 
-          // Allow options for children to be set at the parent options
-          // e.g. videojs(id, { controlBar: false });
-          // instead of videojs(id, { children: { controlBar: false });
-          if (parentOptions[name] !== undefined) {
-            opts = parentOptions[name];
-          }
+exports.__esModule = true;
 
-          // Allow for disabling default components
-          // e.g. options['children']['posterImage'] = false
-          if (opts === false) {
-            return;
-          }
+var _button = _dereq_(2);
 
-          // Allow options to be passed as a simple boolean if no configuration
-          // is necessary.
-          if (opts === true) {
-            opts = {};
-          }
+var _button2 = _interopRequireDefault(_button);
 
-          // We also want to pass the original player options to each component as well so they don't need to
-          // reach back into the player for options later.
-          opts.playerOptions = _this.options_.playerOptions;
+var _component = _dereq_(5);
 
-          // Create and add the child component.
-          // Add a direct reference to the child by name on the parent instance.
-          // If two of the same component are used, different names should be supplied
-          // for each
-          var newChild = _this.addChild(name, opts);
-          if (newChild) {
-            _this[name] = newChild;
-          }
-        };
+var _component2 = _interopRequireDefault(_component);
 
-        // Allow for an array of children details to passed in the options
-        var workingChildren = undefined;
-        var Tech = Component.getComponent('Tech');
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-        if (Array.isArray(children)) {
-          workingChildren = children;
-        } else {
-          workingChildren = Object.keys(children);
-        }
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-        workingChildren
-        // children that are in this.options_ but also in workingChildren  would
-        // give us extra children we do not want. So, we want to filter them out.
-        .concat(Object.keys(_this.options_).filter(function (child) {
-          return !workingChildren.some(function (wchild) {
-            if (typeof wchild === 'string') {
-              return child === wchild;
-            } else {
-              return child === wchild.name;
-            }
-          });
-        })).map(function (child) {
-          var name = undefined,
-              opts = undefined;
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-          if (typeof child === 'string') {
-            name = child;
-            opts = children[name] || _this.options_[name] || {};
-          } else {
-            name = child.name;
-            opts = child;
-          }
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file fullscreen-toggle.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-          return { name: name, opts: opts };
-        }).filter(function (child) {
-          // we have to make sure that child.name isn't in the techOrder since
-          // techs are registerd as Components but can't aren't compatible
-          // See https://github.com/videojs/video.js/issues/2772
-          var c = Component.getComponent(child.opts.componentClass || _utilsToTitleCaseJs2['default'](child.name));
-          return c && !Tech.isTech(c);
-        }).forEach(handleAdd);
-      })();
-    }
-  };
+
+/**
+ * Toggle fullscreen video
+ *
+ * @extends Button
+ * @class FullscreenToggle
+ */
+var FullscreenToggle = function (_Button) {
+  _inherits(FullscreenToggle, _Button);
+
+  function FullscreenToggle(player, options) {
+    _classCallCheck(this, FullscreenToggle);
+
+    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
+
+    _this.on(player, 'fullscreenchange', _this.handleFullscreenChange);
+    return _this;
+  }
 
   /**
-   * Allows sub components to stack CSS class names
+   * Allow sub components to stack CSS class names
    *
    * @return {String} The constructed class name
    * @method buildCSSClass
    */
 
-  Component.prototype.buildCSSClass = function buildCSSClass() {
-    // Child classes can include a function that does:
-    // return 'CLASS NAME' + this._super();
-    return '';
-  };
 
+  FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this);
+  };
   /**
-   * Add an event listener to this component's element
-   * ```js
-   *     var myFunc = function(){
-   *       var myComponent = this;
-   *       // Do something when the event is fired
-   *     };
-   *
-   *     myComponent.on('eventType', myFunc);
-   * ```
-   * The context of myFunc will be myComponent unless previously bound.
-   * Alternatively, you can add a listener to another element or component.
-   * ```js
-   *     myComponent.on(otherElement, 'eventName', myFunc);
-   *     myComponent.on(otherComponent, 'eventName', myFunc);
-   * ```
-   * The benefit of using this over `VjsEvents.on(otherElement, 'eventName', myFunc)`
-   * and `otherComponent.on('eventName', myFunc)` is that this way the listeners
-   * will be automatically cleaned up when either component is disposed.
-   * It will also bind myComponent as the context of myFunc.
-   * **NOTE**: When using this on elements in the page other than window
-   * and document (both permanent), if you remove the element from the DOM
-   * you need to call `myComponent.trigger(el, 'dispose')` on it to clean up
-   * references to it and allow the browser to garbage collect it.
+   * Handles Fullscreenchange on the component and change control text accordingly
    *
-   * @param  {String|Component} first   The event type or other component
-   * @param  {Function|String}      second  The event handler or event type
-   * @param  {Function}             third   The event handler
-   * @return {Component}
-   * @method on
+   * @method handleFullscreenChange
    */
 
-  Component.prototype.on = function on(first, second, third) {
-    var _this2 = this;
 
-    if (typeof first === 'string' || Array.isArray(first)) {
-      Events.on(this.el_, first, Fn.bind(this, second));
+  FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange() {
+    if (this.player_.isFullscreen()) {
+      this.controlText('Non-Fullscreen');
+    } else {
+      this.controlText('Fullscreen');
+    }
+  };
+  /**
+   * Handles click for full screen
+   *
+   * @method handleClick
+   */
 
-      // Targeting another component or element
+
+  FullscreenToggle.prototype.handleClick = function handleClick() {
+    if (!this.player_.isFullscreen()) {
+      this.player_.requestFullscreen();
     } else {
-        (function () {
-          var target = first;
-          var type = second;
-          var fn = Fn.bind(_this2, third);
+      this.player_.exitFullscreen();
+    }
+  };
 
-          // When this component is disposed, remove the listener from the other component
-          var removeOnDispose = function removeOnDispose() {
-            return _this2.off(target, type, fn);
-          };
+  return FullscreenToggle;
+}(_button2['default']);
 
-          // Use the same function ID so we can remove it later it using the ID
-          // of the original listener
-          removeOnDispose.guid = fn.guid;
-          _this2.on('dispose', removeOnDispose);
+FullscreenToggle.prototype.controlText_ = 'Fullscreen';
 
-          // If the other component is disposed first we need to clean the reference
-          // to the other component in this component's removeOnDispose listener
-          // Otherwise we create a memory leak.
-          var cleanRemover = function cleanRemover() {
-            return _this2.off('dispose', removeOnDispose);
-          };
+_component2['default'].registerComponent('FullscreenToggle', FullscreenToggle);
+exports['default'] = FullscreenToggle;
 
-          // Add the same function ID so we can easily remove it later
-          cleanRemover.guid = fn.guid;
-
-          // Check if this is a DOM node
-          if (first.nodeName) {
-            // Add the listener to the other element
-            Events.on(target, type, fn);
-            Events.on(target, 'dispose', cleanRemover);
-
-            // Should be a component
-            // Not using `instanceof Component` because it makes mock players difficult
-          } else if (typeof first.on === 'function') {
-              // Add the listener to the other component
-              target.on(type, fn);
-              target.on('dispose', cleanRemover);
-            }
-        })();
-      }
+},{"2":2,"5":5}],10:[function(_dereq_,module,exports){
+'use strict';
 
-    return this;
-  };
+exports.__esModule = true;
 
-  /**
-   * Remove an event listener from this component's element
-   * ```js
-   *     myComponent.off('eventType', myFunc);
-   * ```
-   * If myFunc is excluded, ALL listeners for the event type will be removed.
-   * If eventType is excluded, ALL listeners will be removed from the component.
-   * Alternatively you can use `off` to remove listeners that were added to other
-   * elements or components using `myComponent.on(otherComponent...`.
-   * In this case both the event type and listener function are REQUIRED.
-   * ```js
-   *     myComponent.off(otherElement, 'eventType', myFunc);
-   *     myComponent.off(otherComponent, 'eventType', myFunc);
-   * ```
-   *
-   * @param  {String=|Component}  first  The event type or other component
-   * @param  {Function=|String}       second The listener function or event type
-   * @param  {Function=}              third  The listener for other component
-   * @return {Component}
-   * @method off
-   */
+var _component = _dereq_(5);
 
-  Component.prototype.off = function off(first, second, third) {
-    if (!first || typeof first === 'string' || Array.isArray(first)) {
-      Events.off(this.el_, first, second);
-    } else {
-      var target = first;
-      var type = second;
-      // Ensure there's at least a guid, even if the function hasn't been used
-      var fn = Fn.bind(this, third);
+var _component2 = _interopRequireDefault(_component);
 
-      // Remove the dispose listener on this component,
-      // which was given the same guid as the event listener
-      this.off('dispose', fn);
+var _dom = _dereq_(80);
 
-      if (first.nodeName) {
-        // Remove the listener
-        Events.off(target, type, fn);
-        // Remove the listener for cleaning the dispose listener
-        Events.off(target, 'dispose', fn);
-      } else {
-        target.off(type, fn);
-        target.off('dispose', fn);
-      }
-    }
+var Dom = _interopRequireWildcard(_dom);
 
-    return this;
-  };
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-  /**
-   * Add an event listener to be triggered only once and then removed
-   * ```js
-   *     myComponent.one('eventName', myFunc);
-   * ```
-   * Alternatively you can add a listener to another element or component
-   * that will be triggered only once.
-   * ```js
-   *     myComponent.one(otherElement, 'eventName', myFunc);
-   *     myComponent.one(otherComponent, 'eventName', myFunc);
-   * ```
-   *
-   * @param  {String|Component}  first   The event type or other component
-   * @param  {Function|String}       second  The listener function or event type
-   * @param  {Function=}             third   The listener function for other component
-   * @return {Component}
-   * @method one
-   */
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-  Component.prototype.one = function one(first, second, third) {
-    var _this3 = this,
-        _arguments = arguments;
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-    if (typeof first === 'string' || Array.isArray(first)) {
-      Events.one(this.el_, first, Fn.bind(this, second));
-    } else {
-      (function () {
-        var target = first;
-        var type = second;
-        var fn = Fn.bind(_this3, third);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-        var newFunc = function newFunc() {
-          _this3.off(target, type, newFunc);
-          fn.apply(null, _arguments);
-        };
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file live-display.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-        // Keep the same function ID so we can remove it later
-        newFunc.guid = fn.guid;
 
-        _this3.on(target, type, newFunc);
-      })();
-    }
+/**
+ * Displays the live indicator
+ * TODO - Future make it click to snap to live
+ *
+ * @extends Component
+ * @class LiveDisplay
+ */
+var LiveDisplay = function (_Component) {
+  _inherits(LiveDisplay, _Component);
 
-    return this;
-  };
+  function LiveDisplay(player, options) {
+    _classCallCheck(this, LiveDisplay);
 
-  /**
-   * Trigger an event on an element
-   * ```js
-   *     myComponent.trigger('eventName');
-   *     myComponent.trigger({'type':'eventName'});
-   *     myComponent.trigger('eventName', {data: 'some data'});
-   *     myComponent.trigger({'type':'eventName'}, {data: 'some data'});
-   * ```
-   *
-   * @param  {Event|Object|String} event  A string (the type) or an event object with a type attribute
-   * @param  {Object} [hash] data hash to pass along with the event
-   * @return {Component}       self
-   * @method trigger
-   */
+    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
 
-  Component.prototype.trigger = function trigger(event, hash) {
-    Events.trigger(this.el_, event, hash);
-    return this;
-  };
+    _this.updateShowing();
+    _this.on(_this.player(), 'durationchange', _this.updateShowing);
+    return _this;
+  }
 
   /**
-   * Bind a listener to the component's ready state.
-   * Different from event listeners in that if the ready event has already happened
-   * it will trigger the function immediately.
+   * Create the component's DOM element
    *
-   * @param  {Function} fn Ready listener
-   * @param  {Boolean} sync Exec the listener synchronously if component is ready
-   * @return {Component}
-   * @method ready
+   * @return {Element}
+   * @method createEl
    */
 
-  Component.prototype.ready = function ready(fn) {
-    var sync = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
 
-    if (fn) {
-      if (this.isReady_) {
-        if (sync) {
-          fn.call(this);
-        } else {
-          // Call the function asynchronously by default for consistency
-          this.setTimeout(fn, 1);
-        }
-      } else {
-        this.readyQueue_ = this.readyQueue_ || [];
-        this.readyQueue_.push(fn);
-      }
+  LiveDisplay.prototype.createEl = function createEl() {
+    var el = _Component.prototype.createEl.call(this, 'div', {
+      className: 'vjs-live-control vjs-control'
+    });
+
+    this.contentEl_ = Dom.createEl('div', {
+      className: 'vjs-live-display',
+      innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '</span>' + this.localize('LIVE')
+    }, {
+      'aria-live': 'off'
+    });
+
+    el.appendChild(this.contentEl_);
+    return el;
+  };
+
+  LiveDisplay.prototype.updateShowing = function updateShowing() {
+    if (this.player().duration() === Infinity) {
+      this.show();
+    } else {
+      this.hide();
     }
-    return this;
   };
 
-  /**
-   * Trigger the ready listeners
-   *
-   * @return {Component}
-   * @method triggerReady
-   */
+  return LiveDisplay;
+}(_component2['default']);
 
-  Component.prototype.triggerReady = function triggerReady() {
-    this.isReady_ = true;
+_component2['default'].registerComponent('LiveDisplay', LiveDisplay);
+exports['default'] = LiveDisplay;
 
-    // Ensure ready is triggerd asynchronously
-    this.setTimeout(function () {
-      var readyQueue = this.readyQueue_;
+},{"5":5,"80":80}],11:[function(_dereq_,module,exports){
+'use strict';
 
-      // Reset Ready Queue
-      this.readyQueue_ = [];
+exports.__esModule = true;
 
-      if (readyQueue && readyQueue.length > 0) {
-        readyQueue.forEach(function (fn) {
-          fn.call(this);
-        }, this);
-      }
+var _button = _dereq_(2);
 
-      // Allow for using event listeners also
-      this.trigger('ready');
-    }, 1);
-  };
+var _button2 = _interopRequireDefault(_button);
 
-  /**
-   * Finds a single DOM element matching `selector` within the component's
-   * `contentEl` or another custom context.
-   *
-   * @method $
-   * @param  {String} selector
-   *         A valid CSS selector, which will be passed to `querySelector`.
-   *
-   * @param  {Element|String} [context=document]
-   *         A DOM element within which to query. Can also be a selector
-   *         string in which case the first matching element will be used
-   *         as context. If missing (or no element matches selector), falls
-   *         back to `document`.
-   *
-   * @return {Element|null}
-   */
+var _component = _dereq_(5);
 
-  Component.prototype.$ = function $(selector, context) {
-    return Dom.$(selector, context || this.contentEl());
-  };
+var _component2 = _interopRequireDefault(_component);
 
-  /**
-   * Finds a all DOM elements matching `selector` within the component's
-   * `contentEl` or another custom context.
-   *
-   * @method $$
-   * @param  {String} selector
-   *         A valid CSS selector, which will be passed to `querySelectorAll`.
-   *
-   * @param  {Element|String} [context=document]
-   *         A DOM element within which to query. Can also be a selector
-   *         string in which case the first matching element will be used
-   *         as context. If missing (or no element matches selector), falls
-   *         back to `document`.
-   *
-   * @return {NodeList}
-   */
+var _dom = _dereq_(80);
 
-  Component.prototype.$$ = function $$(selector, context) {
-    return Dom.$$(selector, context || this.contentEl());
-  };
+var Dom = _interopRequireWildcard(_dom);
 
-  /**
-   * Check if a component's element has a CSS class name
-   *
-   * @param {String} classToCheck Classname to check
-   * @return {Component}
-   * @method hasClass
-   */
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file mute-toggle.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-  Component.prototype.hasClass = function hasClass(classToCheck) {
-    return Dom.hasElClass(this.el_, classToCheck);
-  };
+
+/**
+ * A button component for muting the audio
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends Button
+ * @class MuteToggle
+ */
+var MuteToggle = function (_Button) {
+  _inherits(MuteToggle, _Button);
+
+  function MuteToggle(player, options) {
+    _classCallCheck(this, MuteToggle);
+
+    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
+
+    _this.on(player, 'volumechange', _this.update);
+
+    // hide mute toggle if the current tech doesn't support volume control
+    if (player.tech_ && player.tech_.featuresVolumeControl === false) {
+      _this.addClass('vjs-hidden');
+    }
+
+    _this.on(player, 'loadstart', function () {
+      // We need to update the button to account for a default muted state.
+      this.update();
+
+      if (player.tech_.featuresVolumeControl === false) {
+        this.addClass('vjs-hidden');
+      } else {
+        this.removeClass('vjs-hidden');
+      }
+    });
+    return _this;
+  }
 
   /**
-   * Add a CSS class name to the component's element
+   * Allow sub components to stack CSS class names
    *
-   * @param {String} classToAdd Classname to add
-   * @return {Component}
-   * @method addClass
+   * @return {String} The constructed class name
+   * @method buildCSSClass
    */
 
-  Component.prototype.addClass = function addClass(classToAdd) {
-    Dom.addElClass(this.el_, classToAdd);
-    return this;
+
+  MuteToggle.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Remove a CSS class name from the component's element
+   * Handle click on mute
    *
-   * @param {String} classToRemove Classname to remove
-   * @return {Component}
-   * @method removeClass
+   * @method handleClick
    */
 
-  Component.prototype.removeClass = function removeClass(classToRemove) {
-    Dom.removeElClass(this.el_, classToRemove);
-    return this;
+
+  MuteToggle.prototype.handleClick = function handleClick() {
+    this.player_.muted(this.player_.muted() ? false : true);
   };
 
   /**
-   * Add or remove a CSS class name from the component's element
-   *
-   * @param  {String} classToToggle
-   * @param  {Boolean|Function} [predicate]
-   *         Can be a function that returns a Boolean. If `true`, the class
-   *         will be added; if `false`, the class will be removed. If not
-   *         given, the class will be added if not present and vice versa.
+   * Update volume
    *
-   * @return {Component}
-   * @method toggleClass
+   * @method update
    */
 
-  Component.prototype.toggleClass = function toggleClass(classToToggle, predicate) {
-    Dom.toggleElClass(this.el_, classToToggle, predicate);
-    return this;
-  };
 
-  /**
-   * Show the component element if hidden
-   *
-   * @return {Component}
-   * @method show
-   */
+  MuteToggle.prototype.update = function update() {
+    var vol = this.player_.volume();
+    var level = 3;
 
-  Component.prototype.show = function show() {
-    this.removeClass('vjs-hidden');
-    return this;
-  };
+    if (vol === 0 || this.player_.muted()) {
+      level = 0;
+    } else if (vol < 0.33) {
+      level = 1;
+    } else if (vol < 0.67) {
+      level = 2;
+    }
 
-  /**
-   * Hide the component element if currently showing
-   *
-   * @return {Component}
-   * @method hide
-   */
+    // Don't rewrite the button text if the actual text doesn't change.
+    // This causes unnecessary and confusing information for screen reader users.
+    // This check is needed because this function gets called every time the volume level is changed.
+    var toMute = this.player_.muted() ? 'Unmute' : 'Mute';
 
-  Component.prototype.hide = function hide() {
-    this.addClass('vjs-hidden');
-    return this;
+    if (this.controlText() !== toMute) {
+      this.controlText(toMute);
+    }
+
+    // TODO improve muted icon classes
+    for (var i = 0; i < 4; i++) {
+      Dom.removeElClass(this.el_, 'vjs-vol-' + i);
+    }
+    Dom.addElClass(this.el_, 'vjs-vol-' + level);
   };
 
-  /**
-   * Lock an item in its visible state
-   * To be used with fadeIn/fadeOut.
-   *
-   * @return {Component}
-   * @private
-   * @method lockShowing
-   */
+  return MuteToggle;
+}(_button2['default']);
 
-  Component.prototype.lockShowing = function lockShowing() {
-    this.addClass('vjs-lock-showing');
-    return this;
-  };
+MuteToggle.prototype.controlText_ = 'Mute';
 
-  /**
-   * Unlock an item to be hidden
-   * To be used with fadeIn/fadeOut.
-   *
-   * @return {Component}
-   * @private
-   * @method unlockShowing
-   */
+_component2['default'].registerComponent('MuteToggle', MuteToggle);
+exports['default'] = MuteToggle;
 
-  Component.prototype.unlockShowing = function unlockShowing() {
-    this.removeClass('vjs-lock-showing');
-    return this;
-  };
+},{"2":2,"5":5,"80":80}],12:[function(_dereq_,module,exports){
+'use strict';
+
+exports.__esModule = true;
+
+var _button = _dereq_(2);
+
+var _button2 = _interopRequireDefault(_button);
+
+var _component = _dereq_(5);
+
+var _component2 = _interopRequireDefault(_component);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-toggle.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
+
+
+/**
+ * Button to toggle between play and pause
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends Button
+ * @class PlayToggle
+ */
+var PlayToggle = function (_Button) {
+  _inherits(PlayToggle, _Button);
+
+  function PlayToggle(player, options) {
+    _classCallCheck(this, PlayToggle);
+
+    var _this = _possibleConstructorReturn(this, _Button.call(this, player, options));
+
+    _this.on(player, 'play', _this.handlePlay);
+    _this.on(player, 'pause', _this.handlePause);
+    return _this;
+  }
 
   /**
-   * Set or get the width of the component (CSS values)
-   * Setting the video tag dimension values only works with values in pixels.
-   * Percent values will not work.
-   * Some percents can be used, but width()/height() will return the number + %,
-   * not the actual computed width/height.
+   * Allow sub components to stack CSS class names
    *
-   * @param  {Number|String=} num   Optional width number
-   * @param  {Boolean} skipListeners Skip the 'resize' event trigger
-   * @return {Component} This component, when setting the width
-   * @return {Number|String} The width, when getting
-   * @method width
+   * @return {String} The constructed class name
+   * @method buildCSSClass
    */
 
-  Component.prototype.width = function width(num, skipListeners) {
-    return this.dimension('width', num, skipListeners);
+
+  PlayToggle.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Get or set the height of the component (CSS values)
-   * Setting the video tag dimension values only works with values in pixels.
-   * Percent values will not work.
-   * Some percents can be used, but width()/height() will return the number + %,
-   * not the actual computed width/height.
+   * Handle click to toggle between play and pause
    *
-   * @param  {Number|String=} num     New component height
-   * @param  {Boolean=} skipListeners Skip the resize event trigger
-   * @return {Component} This component, when setting the height
-   * @return {Number|String} The height, when getting
-   * @method height
+   * @method handleClick
    */
 
-  Component.prototype.height = function height(num, skipListeners) {
-    return this.dimension('height', num, skipListeners);
+
+  PlayToggle.prototype.handleClick = function handleClick() {
+    if (this.player_.paused()) {
+      this.player_.play();
+    } else {
+      this.player_.pause();
+    }
   };
 
   /**
-   * Set both width and height at the same time
+   * Add the vjs-playing class to the element so it can change appearance
    *
-   * @param  {Number|String} width Width of player
-   * @param  {Number|String} height Height of player
-   * @return {Component} The component
-   * @method dimensions
+   * @method handlePlay
    */
 
-  Component.prototype.dimensions = function dimensions(width, height) {
-    // Skip resize listeners on width for optimization
-    return this.width(width, true).height(height);
+
+  PlayToggle.prototype.handlePlay = function handlePlay() {
+    this.removeClass('vjs-paused');
+    this.addClass('vjs-playing');
+    // change the button text to "Pause"
+    this.controlText('Pause');
   };
 
   /**
-   * Get or set width or height
-   * This is the shared code for the width() and height() methods.
-   * All for an integer, integer + 'px' or integer + '%';
-   * Known issue: Hidden elements officially have a width of 0. We're defaulting
-   * to the style.width value and falling back to computedStyle which has the
-   * hidden element issue. Info, but probably not an efficient fix:
-   * http://www.foliotek.com/devblog/getting-the-width-of-a-hidden-element-with-jquery-using-width/
+   * Add the vjs-paused class to the element so it can change appearance
    *
-   * @param  {String} widthOrHeight  'width' or 'height'
-   * @param  {Number|String=} num     New dimension
-   * @param  {Boolean=} skipListeners Skip resize event trigger
-   * @return {Component} The component if a dimension was set
-   * @return {Number|String} The dimension if nothing was set
-   * @private
-   * @method dimension
+   * @method handlePause
    */
 
-  Component.prototype.dimension = function dimension(widthOrHeight, num, skipListeners) {
-    if (num !== undefined) {
-      // Set to zero if null or literally NaN (NaN !== NaN)
-      if (num === null || num !== num) {
-        num = 0;
-      }
 
-      // Check if using css width/height (% or px) and adjust
-      if (('' + num).indexOf('%') !== -1 || ('' + num).indexOf('px') !== -1) {
-        this.el_.style[widthOrHeight] = num;
-      } else if (num === 'auto') {
-        this.el_.style[widthOrHeight] = '';
-      } else {
-        this.el_.style[widthOrHeight] = num + 'px';
-      }
+  PlayToggle.prototype.handlePause = function handlePause() {
+    this.removeClass('vjs-playing');
+    this.addClass('vjs-paused');
+    // change the button text to "Play"
+    this.controlText('Play');
+  };
 
-      // skipListeners allows us to avoid triggering the resize event when setting both width and height
-      if (!skipListeners) {
-        this.trigger('resize');
-      }
+  return PlayToggle;
+}(_button2['default']);
 
-      // Return component
-      return this;
-    }
+PlayToggle.prototype.controlText_ = 'Play';
 
-    // Not setting a value, so getting it
-    // Make sure element exists
-    if (!this.el_) {
-      return 0;
-    }
+_component2['default'].registerComponent('PlayToggle', PlayToggle);
+exports['default'] = PlayToggle;
 
-    // Get dimension value from style
-    var val = this.el_.style[widthOrHeight];
-    var pxIndex = val.indexOf('px');
+},{"2":2,"5":5}],13:[function(_dereq_,module,exports){
+'use strict';
 
-    if (pxIndex !== -1) {
-      // Return the pixel value with no 'px'
-      return parseInt(val.slice(0, pxIndex), 10);
-    }
+exports.__esModule = true;
 
-    // No px so using % or no style was set, so falling back to offsetWidth/height
-    // If component has display:none, offset will return 0
-    // TODO: handle display:none and no dimension style using px
-    return parseInt(this.el_['offset' + _utilsToTitleCaseJs2['default'](widthOrHeight)], 10);
-  };
+var _menuButton = _dereq_(47);
 
-  /**
-   * Get width or height of computed style
-   * @param  {String} widthOrHeight  'width' or 'height'
-   * @return {Number|Boolean} The bolean false if nothing was set
-   * @method currentDimension
-   */
+var _menuButton2 = _interopRequireDefault(_menuButton);
 
-  Component.prototype.currentDimension = function currentDimension(widthOrHeight) {
-    var computedWidthOrHeight = 0;
+var _menu = _dereq_(49);
 
-    if (widthOrHeight !== 'width' && widthOrHeight !== 'height') {
-      throw new Error('currentDimension only accepts width or height value');
-    }
+var _menu2 = _interopRequireDefault(_menu);
 
-    if (typeof _globalWindow2['default'].getComputedStyle === 'function') {
-      var computedStyle = _globalWindow2['default'].getComputedStyle(this.el_);
-      computedWidthOrHeight = computedStyle.getPropertyValue(widthOrHeight) || computedStyle[widthOrHeight];
-    } else if (this.el_.currentStyle) {
-      // ie 8 doesn't support computed style, shim it
-      // return clientWidth or clientHeight instead for better accuracy
-      var rule = 'offset' + _utilsToTitleCaseJs2['default'](widthOrHeight);
-      computedWidthOrHeight = this.el_[rule];
-    }
+var _playbackRateMenuItem = _dereq_(14);
 
-    // remove 'px' from variable and parse as integer
-    computedWidthOrHeight = parseFloat(computedWidthOrHeight);
-    return computedWidthOrHeight;
-  };
+var _playbackRateMenuItem2 = _interopRequireDefault(_playbackRateMenuItem);
 
-  /**
-   * Get an object which contains width and height values of computed style
-   * @return {Object} The dimensions of element
-   * @method currentDimensions
-   */
+var _component = _dereq_(5);
 
-  Component.prototype.currentDimensions = function currentDimensions() {
-    return {
-      width: this.currentDimension('width'),
-      height: this.currentDimension('height')
-    };
-  };
+var _component2 = _interopRequireDefault(_component);
 
-  /**
-   * Get width of computed style
-   * @return {Integer}
-   * @method currentWidth
-   */
+var _dom = _dereq_(80);
 
-  Component.prototype.currentWidth = function currentWidth() {
-    return this.currentDimension('width');
-  };
+var Dom = _interopRequireWildcard(_dom);
 
-  /**
-   * Get height of computed style
-   * @return {Integer}
-   * @method currentHeight
-   */
-
-  Component.prototype.currentHeight = function currentHeight() {
-    return this.currentDimension('height');
-  };
-
-  /**
-   * Emit 'tap' events when touch events are supported
-   * This is used to support toggling the controls through a tap on the video.
-   * We're requiring them to be enabled because otherwise every component would
-   * have this extra overhead unnecessarily, on mobile devices where extra
-   * overhead is especially bad.
-   *
-   * @private
-   * @method emitTapEvents
-   */
-
-  Component.prototype.emitTapEvents = function emitTapEvents() {
-    // Track the start time so we can determine how long the touch lasted
-    var touchStart = 0;
-    var firstTouch = null;
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-    // Maximum movement allowed during a touch event to still be considered a tap
-    // Other popular libs use anywhere from 2 (hammer.js) to 15, so 10 seems like a nice, round number.
-    var tapMovementThreshold = 10;
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-    // The maximum length a touch can be while still being considered a tap
-    var touchTimeThreshold = 200;
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-    var couldBeTap = undefined;
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-    this.on('touchstart', function (event) {
-      // If more than one finger, don't consider treating this as a click
-      if (event.touches.length === 1) {
-        // Copy pageX/pageY from the object
-        firstTouch = {
-          pageX: event.touches[0].pageX,
-          pageY: event.touches[0].pageY
-        };
-        // Record start time so we can detect a tap vs. "touch and hold"
-        touchStart = new Date().getTime();
-        // Reset couldBeTap tracking
-        couldBeTap = true;
-      }
-    });
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file playback-rate-menu-button.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-    this.on('touchmove', function (event) {
-      // If more than one finger, don't consider treating this as a click
-      if (event.touches.length > 1) {
-        couldBeTap = false;
-      } else if (firstTouch) {
-        // Some devices will throw touchmoves for all but the slightest of taps.
-        // So, if we moved only a small distance, this could still be a tap
-        var xdiff = event.touches[0].pageX - firstTouch.pageX;
-        var ydiff = event.touches[0].pageY - firstTouch.pageY;
-        var touchDistance = Math.sqrt(xdiff * xdiff + ydiff * ydiff);
 
-        if (touchDistance > tapMovementThreshold) {
-          couldBeTap = false;
-        }
-      }
-    });
+/**
+ * The component for controlling the playback rate
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends MenuButton
+ * @class PlaybackRateMenuButton
+ */
+var PlaybackRateMenuButton = function (_MenuButton) {
+  _inherits(PlaybackRateMenuButton, _MenuButton);
 
-    var noTap = function noTap() {
-      couldBeTap = false;
-    };
+  function PlaybackRateMenuButton(player, options) {
+    _classCallCheck(this, PlaybackRateMenuButton);
 
-    // TODO: Listen to the original target. http://youtu.be/DujfpXOKUp8?t=13m8s
-    this.on('touchleave', noTap);
-    this.on('touchcancel', noTap);
+    var _this = _possibleConstructorReturn(this, _MenuButton.call(this, player, options));
 
-    // When the touch ends, measure how long it took and trigger the appropriate
-    // event
-    this.on('touchend', function (event) {
-      firstTouch = null;
-      // Proceed only if the touchmove/leave/cancel event didn't happen
-      if (couldBeTap === true) {
-        // Measure how long the touch lasted
-        var touchTime = new Date().getTime() - touchStart;
+    _this.updateVisibility();
+    _this.updateLabel();
 
-        // Make sure the touch was less than the threshold to be considered a tap
-        if (touchTime < touchTimeThreshold) {
-          // Don't let browser turn this into a click
-          event.preventDefault();
-          this.trigger('tap');
-          // It may be good to copy the touchend event object and change the
-          // type to tap, if the other event properties aren't exact after
-          // Events.fixEvent runs (e.g. event.target)
-        }
-      }
-    });
-  };
+    _this.on(player, 'loadstart', _this.updateVisibility);
+    _this.on(player, 'ratechange', _this.updateLabel);
+    return _this;
+  }
 
   /**
-   * Report user touch activity when touch events occur
-   * User activity is used to determine when controls should show/hide. It's
-   * relatively simple when it comes to mouse events, because any mouse event
-   * should show the controls. So we capture mouse events that bubble up to the
-   * player and report activity when that happens.
-   * With touch events it isn't as easy. We can't rely on touch events at the
-   * player level, because a tap (touchstart + touchend) on the video itself on
-   * mobile devices is meant to turn controls off (and on). User activity is
-   * checked asynchronously, so what could happen is a tap event on the video
-   * turns the controls off, then the touchend event bubbles up to the player,
-   * which if it reported user activity, would turn the controls right back on.
-   * (We also don't want to completely block touch events from bubbling up)
-   * Also a touchmove, touch+hold, and anything other than a tap is not supposed
-   * to turn the controls back on on a mobile device.
-   * Here we're setting the default component behavior to report user activity
-   * whenever touch events happen, and this can be turned off by components that
-   * want touch events to act differently.
+   * Create the component's DOM element
    *
-   * @method enableTouchActivity
+   * @return {Element}
+   * @method createEl
    */
 
-  Component.prototype.enableTouchActivity = function enableTouchActivity() {
-    // Don't continue if the root player doesn't support reporting user activity
-    if (!this.player() || !this.player().reportUserActivity) {
-      return;
-    }
-
-    // listener for reporting that the user is active
-    var report = Fn.bind(this.player(), this.player().reportUserActivity);
 
-    var touchHolding = undefined;
+  PlaybackRateMenuButton.prototype.createEl = function createEl() {
+    var el = _MenuButton.prototype.createEl.call(this);
 
-    this.on('touchstart', function () {
-      report();
-      // For as long as the they are touching the device or have their mouse down,
-      // we consider them active even if they're not moving their finger or mouse.
-      // So we want to continue to update that they are active
-      this.clearInterval(touchHolding);
-      // report at the same interval as activityCheck
-      touchHolding = this.setInterval(report, 250);
+    this.labelEl_ = Dom.createEl('div', {
+      className: 'vjs-playback-rate-value',
+      innerHTML: 1.0
     });
 
-    var touchEnd = function touchEnd(event) {
-      report();
-      // stop the interval that maintains activity if the touch is holding
-      this.clearInterval(touchHolding);
-    };
+    el.appendChild(this.labelEl_);
 
-    this.on('touchmove', report);
-    this.on('touchend', touchEnd);
-    this.on('touchcancel', touchEnd);
+    return el;
   };
 
   /**
-   * Creates timeout and sets up disposal automatically.
+   * Allow sub components to stack CSS class names
    *
-   * @param {Function} fn The function to run after the timeout.
-   * @param {Number} timeout Number of ms to delay before executing specified function.
-   * @return {Number} Returns the timeout ID
-   * @method setTimeout
+   * @return {String} The constructed class name
+   * @method buildCSSClass
    */
 
-  Component.prototype.setTimeout = function setTimeout(fn, timeout) {
-    fn = Fn.bind(this, fn);
-
-    // window.setTimeout would be preferable here, but due to some bizarre issue with Sinon and/or Phantomjs, we can't.
-    var timeoutId = _globalWindow2['default'].setTimeout(fn, timeout);
-
-    var disposeFn = function disposeFn() {
-      this.clearTimeout(timeoutId);
-    };
-
-    disposeFn.guid = 'vjs-timeout-' + timeoutId;
-
-    this.on('dispose', disposeFn);
 
-    return timeoutId;
+  PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Clears a timeout and removes the associated dispose listener
+   * Create the playback rate menu
    *
-   * @param {Number} timeoutId The id of the timeout to clear
-   * @return {Number} Returns the timeout ID
-   * @method clearTimeout
+   * @return {Menu} Menu object populated with items
+   * @method createMenu
    */
 
-  Component.prototype.clearTimeout = function clearTimeout(timeoutId) {
-    _globalWindow2['default'].clearTimeout(timeoutId);
-
-    var disposeFn = function disposeFn() {};
 
-    disposeFn.guid = 'vjs-timeout-' + timeoutId;
+  PlaybackRateMenuButton.prototype.createMenu = function createMenu() {
+    var menu = new _menu2['default'](this.player());
+    var rates = this.playbackRates();
 
-    this.off('dispose', disposeFn);
+    if (rates) {
+      for (var i = rates.length - 1; i >= 0; i--) {
+        menu.addChild(new _playbackRateMenuItem2['default'](this.player(), { rate: rates[i] + 'x' }));
+      }
+    }
 
-    return timeoutId;
+    return menu;
   };
 
   /**
-   * Creates an interval and sets up disposal automatically.
+   * Updates ARIA accessibility attributes
    *
-   * @param {Function} fn The function to run every N seconds.
-   * @param {Number} interval Number of ms to delay before executing specified function.
-   * @return {Number} Returns the interval ID
-   * @method setInterval
+   * @method updateARIAAttributes
    */
 
-  Component.prototype.setInterval = function setInterval(fn, interval) {
-    fn = Fn.bind(this, fn);
-
-    var intervalId = _globalWindow2['default'].setInterval(fn, interval);
-
-    var disposeFn = function disposeFn() {
-      this.clearInterval(intervalId);
-    };
-
-    disposeFn.guid = 'vjs-interval-' + intervalId;
-
-    this.on('dispose', disposeFn);
 
-    return intervalId;
+  PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() {
+    // Current playback rate
+    this.el().setAttribute('aria-valuenow', this.player().playbackRate());
   };
 
   /**
-   * Clears an interval and removes the associated dispose listener
+   * Handle menu item click
    *
-   * @param {Number} intervalId The id of the interval to clear
-   * @return {Number} Returns the interval ID
-   * @method clearInterval
+   * @method handleClick
    */
 
-  Component.prototype.clearInterval = function clearInterval(intervalId) {
-    _globalWindow2['default'].clearInterval(intervalId);
-
-    var disposeFn = function disposeFn() {};
 
-    disposeFn.guid = 'vjs-interval-' + intervalId;
+  PlaybackRateMenuButton.prototype.handleClick = function handleClick() {
+    // select next rate option
+    var currentRate = this.player().playbackRate();
+    var rates = this.playbackRates();
 
-    this.off('dispose', disposeFn);
+    // this will select first one if the last one currently selected
+    var newRate = rates[0];
 
-    return intervalId;
+    for (var i = 0; i < rates.length; i++) {
+      if (rates[i] > currentRate) {
+        newRate = rates[i];
+        break;
+      }
+    }
+    this.player().playbackRate(newRate);
   };
 
   /**
-   * Registers a component
+   * Get possible playback rates
    *
-   * @param {String} name Name of the component to register
-   * @param {Object} comp The component to register
-   * @static
-   * @method registerComponent
+   * @return {Array} Possible playback rates
+   * @method playbackRates
    */
 
-  Component.registerComponent = function registerComponent(name, comp) {
-    if (!Component.components_) {
-      Component.components_ = {};
-    }
 
-    Component.components_[name] = comp;
-    return comp;
+  PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() {
+    return this.options_.playbackRates || this.options_.playerOptions && this.options_.playerOptions.playbackRates;
   };
 
   /**
-   * Gets a component by name
+   * Get whether playback rates is supported by the tech
+   * and an array of playback rates exists
    *
-   * @param {String} name Name of the component to get
-   * @return {Component}
-   * @static
-   * @method getComponent
+   * @return {Boolean} Whether changing playback rate is supported
+   * @method playbackRateSupported
    */
 
-  Component.getComponent = function getComponent(name) {
-    if (Component.components_ && Component.components_[name]) {
-      return Component.components_[name];
-    }
 
-    if (_globalWindow2['default'] && _globalWindow2['default'].videojs && _globalWindow2['default'].videojs[name]) {
-      _utilsLogJs2['default'].warn('The ' + name + ' component was added to the videojs object when it should be registered using videojs.registerComponent(name, component)');
-      return _globalWindow2['default'].videojs[name];
-    }
+  PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() {
+    return this.player().tech_ && this.player().tech_.featuresPlaybackRate && this.playbackRates() && this.playbackRates().length > 0;
   };
 
   /**
-   * Sets up the constructor using the supplied init method
-   * or uses the init of the parent object
+   * Hide playback rate controls when they're no playback rate options to select
    *
-   * @param {Object} props An object of properties
-   * @static
-   * @deprecated
-   * @method extend
+   * @method updateVisibility
    */
 
-  Component.extend = function extend(props) {
-    props = props || {};
-
-    _utilsLogJs2['default'].warn('Component.extend({}) has been deprecated, use videojs.extend(Component, {}) instead');
 
-    // Set up the constructor using the supplied init method
-    // or using the init of the parent object
-    // Make sure to check the unobfuscated version for external libs
-    var init = props.init || props.init || this.prototype.init || this.prototype.init || function () {};
-    // In Resig's simple class inheritance (previously used) the constructor
-    //  is a function that calls `this.init.apply(arguments)`
-    // However that would prevent us from using `ParentObject.call(this);`
-    //  in a Child constructor because the `this` in `this.init`
-    //  would still refer to the Child and cause an infinite loop.
-    // We would instead have to do
-    //    `ParentObject.prototype.init.apply(this, arguments);`
-    //  Bleh. We're not creating a _super() function, so it's good to keep
-    //  the parent constructor reference simple.
-    var subObj = function subObj() {
-      init.apply(this, arguments);
-    };
+  PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility() {
+    if (this.playbackRateSupported()) {
+      this.removeClass('vjs-hidden');
+    } else {
+      this.addClass('vjs-hidden');
+    }
+  };
 
-    // Inherit from this object's prototype
-    subObj.prototype = Object.create(this.prototype);
-    // Reset the constructor property for subObj otherwise
-    // instances of subObj would have the constructor of the parent Object
-    subObj.prototype.constructor = subObj;
+  /**
+   * Update button label when rate changed
+   *
+   * @method updateLabel
+   */
 
-    // Make the class extendable
-    subObj.extend = Component.extend;
 
-    // Extend subObj's prototype with functions and other properties from props
-    for (var _name in props) {
-      if (props.hasOwnProperty(_name)) {
-        subObj.prototype[_name] = props[_name];
-      }
+  PlaybackRateMenuButton.prototype.updateLabel = function updateLabel() {
+    if (this.playbackRateSupported()) {
+      this.labelEl_.innerHTML = this.player().playbackRate() + 'x';
     }
-
-    return subObj;
   };
 
-  return Component;
-})();
+  return PlaybackRateMenuButton;
+}(_menuButton2['default']);
 
-Component.registerComponent('Component', Component);
-exports['default'] = Component;
-module.exports = exports['default'];
+PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate';
 
-},{"./utils/dom.js":142,"./utils/events.js":143,"./utils/fn.js":144,"./utils/guid.js":146,"./utils/log.js":147,"./utils/merge-options.js":148,"./utils/to-title-case.js":151,"global/window":2}],68:[function(_dereq_,module,exports){
-/**
- * @file audio-track-button.js
- */
+_component2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
+exports['default'] = PlaybackRateMenuButton;
+
+},{"14":14,"47":47,"49":49,"5":5,"80":80}],14:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
-
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var _menuItem = _dereq_(48);
 
-var _trackButtonJs = _dereq_('../track-button.js');
+var _menuItem2 = _interopRequireDefault(_menuItem);
 
-var _trackButtonJs2 = _interopRequireDefault(_trackButtonJs);
+var _component = _dereq_(5);
 
-var _componentJs = _dereq_('../../component.js');
+var _component2 = _interopRequireDefault(_component);
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _utilsFnJs = _dereq_('../../utils/fn.js');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var Fn = _interopRequireWildcard(_utilsFnJs);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _audioTrackMenuItemJs = _dereq_('./audio-track-menu-item.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file playback-rate-menu-item.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var _audioTrackMenuItemJs2 = _interopRequireDefault(_audioTrackMenuItemJs);
 
 /**
- * The base class for buttons that toggle specific text track types (e.g. subtitles)
+ * The specific menu item type for selecting a playback rate
  *
  * @param {Player|Object} player
  * @param {Object=} options
- * @extends TrackButton
- * @class AudioTrackButton
+ * @extends MenuItem
+ * @class PlaybackRateMenuItem
  */
+var PlaybackRateMenuItem = function (_MenuItem) {
+  _inherits(PlaybackRateMenuItem, _MenuItem);
 
-var AudioTrackButton = (function (_TrackButton) {
-  _inherits(AudioTrackButton, _TrackButton);
+  function PlaybackRateMenuItem(player, options) {
+    _classCallCheck(this, PlaybackRateMenuItem);
 
-  function AudioTrackButton(player) {
-    var options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+    var label = options.rate;
+    var rate = parseFloat(label, 10);
 
-    _classCallCheck(this, AudioTrackButton);
+    // Modify options for parent MenuItem class's init.
+    options.label = label;
+    options.selected = rate === 1;
 
-    options.tracks = player.audioTracks && player.audioTracks();
+    var _this = _possibleConstructorReturn(this, _MenuItem.call(this, player, options));
 
-    _TrackButton.call(this, player, options);
+    _this.label = label;
+    _this.rate = rate;
 
-    this.el_.setAttribute('aria-label', 'Audio Menu');
+    _this.on(player, 'ratechange', _this.update);
+    return _this;
   }
 
   /**
-   * Allow sub components to stack CSS class names
+   * Handle click on menu item
    *
-   * @return {String} The constructed class name
-   * @method buildCSSClass
+   * @method handleClick
    */
 
-  AudioTrackButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-audio-button ' + _TrackButton.prototype.buildCSSClass.call(this);
+
+  PlaybackRateMenuItem.prototype.handleClick = function handleClick() {
+    _MenuItem.prototype.handleClick.call(this);
+    this.player().playbackRate(this.rate);
   };
 
   /**
-   * Create a menu item for each audio track
+   * Update playback rate with selected rate
    *
-   * @return {Array} Array of menu items
-   * @method createItems
+   * @method update
    */
 
-  AudioTrackButton.prototype.createItems = function createItems() {
-    var items = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
-
-    var tracks = this.player_.audioTracks && this.player_.audioTracks();
-
-    if (!tracks) {
-      return items;
-    }
-
-    for (var i = 0; i < tracks.length; i++) {
-      var track = tracks[i];
-
-      items.push(new _audioTrackMenuItemJs2['default'](this.player_, {
-        // MenuItem is selectable
-        'selectable': true,
-        'track': track
-      }));
-    }
 
-    return items;
+  PlaybackRateMenuItem.prototype.update = function update() {
+    this.selected(this.player().playbackRate() === this.rate);
   };
 
-  return AudioTrackButton;
-})(_trackButtonJs2['default']);
+  return PlaybackRateMenuItem;
+}(_menuItem2['default']);
 
-AudioTrackButton.prototype.controlText_ = 'Audio Track';
-_componentJs2['default'].registerComponent('AudioTrackButton', AudioTrackButton);
-exports['default'] = AudioTrackButton;
-module.exports = exports['default'];
+PlaybackRateMenuItem.prototype.contentElType = 'button';
 
-},{"../../component.js":67,"../../utils/fn.js":144,"../track-button.js":98,"./audio-track-menu-item.js":69}],69:[function(_dereq_,module,exports){
-/**
- * @file audio-track-menu-item.js
- */
+_component2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
+exports['default'] = PlaybackRateMenuItem;
+
+},{"48":48,"5":5}],15:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+var _component = _dereq_(5);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+var _component2 = _interopRequireDefault(_component);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _dom = _dereq_(80);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var Dom = _interopRequireWildcard(_dom);
 
-var _menuMenuItemJs = _dereq_('../../menu/menu-item.js');
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs);
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _componentJs = _dereq_('../../component.js');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _utilsFnJs = _dereq_('../../utils/fn.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file load-progress-bar.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var Fn = _interopRequireWildcard(_utilsFnJs);
 
 /**
- * The audio track menu item
+ * Shows load progress
  *
  * @param {Player|Object} player
  * @param {Object=} options
- * @extends MenuItem
- * @class AudioTrackMenuItem
+ * @extends Component
+ * @class LoadProgressBar
  */
+var LoadProgressBar = function (_Component) {
+  _inherits(LoadProgressBar, _Component);
 
-var AudioTrackMenuItem = (function (_MenuItem) {
-  _inherits(AudioTrackMenuItem, _MenuItem);
-
-  function AudioTrackMenuItem(player, options) {
-    var _this = this;
-
-    _classCallCheck(this, AudioTrackMenuItem);
-
-    var track = options.track;
-    var tracks = player.audioTracks();
-
-    // Modify options for parent MenuItem class's init.
-    options.label = track.label || track.language || 'Unknown';
-    options.selected = track.enabled;
-
-    _MenuItem.call(this, player, options);
-
-    this.track = track;
+  function LoadProgressBar(player, options) {
+    _classCallCheck(this, LoadProgressBar);
 
-    if (tracks) {
-      (function () {
-        var changeHandler = Fn.bind(_this, _this.handleTracksChange);
+    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
 
-        tracks.addEventListener('change', changeHandler);
-        _this.on('dispose', function () {
-          tracks.removeEventListener('change', changeHandler);
-        });
-      })();
-    }
+    _this.partEls_ = [];
+    _this.on(player, 'progress', _this.update);
+    return _this;
   }
 
   /**
-   * Handle click on audio track
+   * Create the component's DOM element
    *
-   * @method handleClick
+   * @return {Element}
+   * @method createEl
    */
 
-  AudioTrackMenuItem.prototype.handleClick = function handleClick(event) {
-    var tracks = this.player_.audioTracks();
-
-    _MenuItem.prototype.handleClick.call(this, event);
-
-    if (!tracks) return;
-
-    for (var i = 0; i < tracks.length; i++) {
-      var track = tracks[i];
 
-      track.enabled = track === this.track;
-    }
+  LoadProgressBar.prototype.createEl = function createEl() {
+    return _Component.prototype.createEl.call(this, 'div', {
+      className: 'vjs-load-progress',
+      innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Loaded') + '</span>: 0%</span>'
+    });
   };
 
   /**
-   * Handle audio track change
+   * Update progress bar
    *
-   * @method handleTracksChange
+   * @method update
    */
 
-  AudioTrackMenuItem.prototype.handleTracksChange = function handleTracksChange(event) {
-    this.selected(this.track.enabled);
-  };
-
-  return AudioTrackMenuItem;
-})(_menuMenuItemJs2['default']);
-
-_componentJs2['default'].registerComponent('AudioTrackMenuItem', AudioTrackMenuItem);
-exports['default'] = AudioTrackMenuItem;
-module.exports = exports['default'];
-
-},{"../../component.js":67,"../../menu/menu-item.js":110,"../../utils/fn.js":144}],70:[function(_dereq_,module,exports){
-/**
- * @file control-bar.js
- */
-'use strict';
-
-exports.__esModule = true;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
-
-var _componentJs = _dereq_('../component.js');
-
-var _componentJs2 = _interopRequireDefault(_componentJs);
-
-// Required children
+  LoadProgressBar.prototype.update = function update() {
+    var buffered = this.player_.buffered();
+    var duration = this.player_.duration();
+    var bufferedEnd = this.player_.bufferedEnd();
+    var children = this.partEls_;
 
-var _playToggleJs = _dereq_('./play-toggle.js');
+    // get the percent width of a time compared to the total end
+    var percentify = function percentify(time, end) {
+      // no NaN
+      var percent = time / end || 0;
 
-var _playToggleJs2 = _interopRequireDefault(_playToggleJs);
+      return (percent >= 1 ? 1 : percent) * 100 + '%';
+    };
 
-var _timeControlsCurrentTimeDisplayJs = _dereq_('./time-controls/current-time-display.js');
+    // update the width of the progress bar
+    this.el_.style.width = percentify(bufferedEnd, duration);
 
-var _timeControlsCurrentTimeDisplayJs2 = _interopRequireDefault(_timeControlsCurrentTimeDisplayJs);
+    // add child elements to represent the individual buffered time ranges
+    for (var i = 0; i < buffered.length; i++) {
+      var start = buffered.start(i);
+      var end = buffered.end(i);
+      var part = children[i];
 
-var _timeControlsDurationDisplayJs = _dereq_('./time-controls/duration-display.js');
+      if (!part) {
+        part = this.el_.appendChild(Dom.createEl());
+        children[i] = part;
+      }
 
-var _timeControlsDurationDisplayJs2 = _interopRequireDefault(_timeControlsDurationDisplayJs);
+      // set the percent based on the width of the progress bar (bufferedEnd)
+      part.style.left = percentify(start, bufferedEnd);
+      part.style.width = percentify(end - start, bufferedEnd);
+    }
 
-var _timeControlsTimeDividerJs = _dereq_('./time-controls/time-divider.js');
+    // remove unused buffered range elements
+    for (var _i = children.length; _i > buffered.length; _i--) {
+      this.el_.removeChild(children[_i - 1]);
+    }
+    children.length = buffered.length;
+  };
 
-var _timeControlsTimeDividerJs2 = _interopRequireDefault(_timeControlsTimeDividerJs);
+  return LoadProgressBar;
+}(_component2['default']);
 
-var _timeControlsRemainingTimeDisplayJs = _dereq_('./time-controls/remaining-time-display.js');
+_component2['default'].registerComponent('LoadProgressBar', LoadProgressBar);
+exports['default'] = LoadProgressBar;
 
-var _timeControlsRemainingTimeDisplayJs2 = _interopRequireDefault(_timeControlsRemainingTimeDisplayJs);
+},{"5":5,"80":80}],16:[function(_dereq_,module,exports){
+'use strict';
 
-var _liveDisplayJs = _dereq_('./live-display.js');
+exports.__esModule = true;
 
-var _liveDisplayJs2 = _interopRequireDefault(_liveDisplayJs);
+var _window = _dereq_(93);
 
-var _progressControlProgressControlJs = _dereq_('./progress-control/progress-control.js');
+var _window2 = _interopRequireDefault(_window);
 
-var _progressControlProgressControlJs2 = _interopRequireDefault(_progressControlProgressControlJs);
+var _component = _dereq_(5);
 
-var _fullscreenToggleJs = _dereq_('./fullscreen-toggle.js');
+var _component2 = _interopRequireDefault(_component);
 
-var _fullscreenToggleJs2 = _interopRequireDefault(_fullscreenToggleJs);
+var _dom = _dereq_(80);
 
-var _volumeControlVolumeControlJs = _dereq_('./volume-control/volume-control.js');
+var Dom = _interopRequireWildcard(_dom);
 
-var _volumeControlVolumeControlJs2 = _interopRequireDefault(_volumeControlVolumeControlJs);
+var _fn = _dereq_(82);
 
-var _volumeMenuButtonJs = _dereq_('./volume-menu-button.js');
+var Fn = _interopRequireWildcard(_fn);
 
-var _volumeMenuButtonJs2 = _interopRequireDefault(_volumeMenuButtonJs);
+var _formatTime = _dereq_(83);
 
-var _muteToggleJs = _dereq_('./mute-toggle.js');
+var _formatTime2 = _interopRequireDefault(_formatTime);
 
-var _muteToggleJs2 = _interopRequireDefault(_muteToggleJs);
+var _throttle = _dereq_(98);
 
-var _textTrackControlsChaptersButtonJs = _dereq_('./text-track-controls/chapters-button.js');
+var _throttle2 = _interopRequireDefault(_throttle);
 
-var _textTrackControlsChaptersButtonJs2 = _interopRequireDefault(_textTrackControlsChaptersButtonJs);
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-var _textTrackControlsDescriptionsButtonJs = _dereq_('./text-track-controls/descriptions-button.js');
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _textTrackControlsDescriptionsButtonJs2 = _interopRequireDefault(_textTrackControlsDescriptionsButtonJs);
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _textTrackControlsSubtitlesButtonJs = _dereq_('./text-track-controls/subtitles-button.js');
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _textTrackControlsSubtitlesButtonJs2 = _interopRequireDefault(_textTrackControlsSubtitlesButtonJs);
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file mouse-time-display.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var _textTrackControlsCaptionsButtonJs = _dereq_('./text-track-controls/captions-button.js');
-
-var _textTrackControlsCaptionsButtonJs2 = _interopRequireDefault(_textTrackControlsCaptionsButtonJs);
-
-var _audioTrackControlsAudioTrackButtonJs = _dereq_('./audio-track-controls/audio-track-button.js');
-
-var _audioTrackControlsAudioTrackButtonJs2 = _interopRequireDefault(_audioTrackControlsAudioTrackButtonJs);
-
-var _playbackRateMenuPlaybackRateMenuButtonJs = _dereq_('./playback-rate-menu/playback-rate-menu-button.js');
-
-var _playbackRateMenuPlaybackRateMenuButtonJs2 = _interopRequireDefault(_playbackRateMenuPlaybackRateMenuButtonJs);
-
-var _spacerControlsCustomControlSpacerJs = _dereq_('./spacer-controls/custom-control-spacer.js');
-
-var _spacerControlsCustomControlSpacerJs2 = _interopRequireDefault(_spacerControlsCustomControlSpacerJs);
 
 /**
- * Container of main controls
+ * The Mouse Time Display component shows the time you will seek to
+ * when hovering over the progress bar
  *
+ * @param {Player|Object} player
+ * @param {Object=} options
  * @extends Component
- * @class ControlBar
+ * @class MouseTimeDisplay
  */
+var MouseTimeDisplay = function (_Component) {
+  _inherits(MouseTimeDisplay, _Component);
 
-var ControlBar = (function (_Component) {
-  _inherits(ControlBar, _Component);
+  function MouseTimeDisplay(player, options) {
+    _classCallCheck(this, MouseTimeDisplay);
 
-  function ControlBar() {
-    _classCallCheck(this, ControlBar);
+    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
+
+    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
+      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
+    }
+
+    if (_this.keepTooltipsInside) {
+      _this.tooltip = Dom.createEl('div', { className: 'vjs-time-tooltip' });
+      _this.el().appendChild(_this.tooltip);
+      _this.addClass('vjs-keep-tooltips-inside');
+    }
+
+    _this.update(0, 0);
 
-    _Component.apply(this, arguments);
+    player.on('ready', function () {
+      _this.on(player.controlBar.progressControl.el(), 'mousemove', (0, _throttle2['default'])(Fn.bind(_this, _this.handleMouseMove), 25));
+    });
+    return _this;
   }
 
   /**
@@ -5070,155 +3402,206 @@ var ControlBar = (function (_Component) {
    * @method createEl
    */
 
-  ControlBar.prototype.createEl = function createEl() {
+
+  MouseTimeDisplay.prototype.createEl = function createEl() {
     return _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-control-bar',
-      dir: 'ltr'
-    }, {
-      'role': 'group' // The control bar is a group, so it can contain menuitems
+      className: 'vjs-mouse-display'
     });
   };
 
-  return ControlBar;
-})(_componentJs2['default']);
+  MouseTimeDisplay.prototype.handleMouseMove = function handleMouseMove(event) {
+    var duration = this.player_.duration();
+    var newTime = this.calculateDistance(event) * duration;
+    var position = event.pageX - Dom.findElPosition(this.el().parentNode).left;
 
-ControlBar.prototype.options_ = {
-  children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'descriptionsButton', 'subtitlesButton', 'captionsButton', 'audioTrackButton', 'fullscreenToggle']
-};
+    this.update(newTime, position);
+  };
 
-_componentJs2['default'].registerComponent('ControlBar', ControlBar);
-exports['default'] = ControlBar;
-module.exports = exports['default'];
+  MouseTimeDisplay.prototype.update = function update(newTime, position) {
+    var time = (0, _formatTime2['default'])(newTime, this.player_.duration());
 
-},{"../component.js":67,"./audio-track-controls/audio-track-button.js":68,"./fullscreen-toggle.js":71,"./live-display.js":72,"./mute-toggle.js":73,"./play-toggle.js":74,"./playback-rate-menu/playback-rate-menu-button.js":75,"./progress-control/progress-control.js":80,"./spacer-controls/custom-control-spacer.js":83,"./text-track-controls/captions-button.js":86,"./text-track-controls/chapters-button.js":87,"./text-track-controls/descriptions-button.js":89,"./text-track-controls/subtitles-button.js":91,"./time-controls/current-time-display.js":94,"./time-controls/duration-display.js":95,"./time-controls/remaining-time-display.js":96,"./time-controls/time-divider.js":97,"./volume-control/volume-control.js":100,"./volume-menu-button.js":102}],71:[function(_dereq_,module,exports){
-/**
- * @file fullscreen-toggle.js
- */
+    this.el().style.left = position + 'px';
+    this.el().setAttribute('data-current-time', time);
+
+    if (this.keepTooltipsInside) {
+      var clampedPosition = this.clampPosition_(position);
+      var difference = position - clampedPosition + 1;
+      var tooltipWidth = parseFloat(_window2['default'].getComputedStyle(this.tooltip).width);
+      var tooltipWidthHalf = tooltipWidth / 2;
+
+      this.tooltip.innerHTML = time;
+      this.tooltip.style.right = '-' + (tooltipWidthHalf - difference) + 'px';
+    }
+  };
+
+  MouseTimeDisplay.prototype.calculateDistance = function calculateDistance(event) {
+    return Dom.getPointerPosition(this.el().parentNode, event).x;
+  };
+
+  /**
+   * This takes in a horizontal position for the bar and returns a clamped position.
+   * Clamped position means that it will keep the position greater than half the width
+   * of the tooltip and smaller than the player width minus half the width o the tooltip.
+   * It will only clamp the position if `keepTooltipsInside` option is set.
+   *
+   * @param {Number} position the position the bar wants to be
+   * @return {Number} newPosition the (potentially) clamped position
+   * @method clampPosition_
+   */
+
+
+  MouseTimeDisplay.prototype.clampPosition_ = function clampPosition_(position) {
+    if (!this.keepTooltipsInside) {
+      return position;
+    }
+
+    var playerWidth = parseFloat(_window2['default'].getComputedStyle(this.player().el()).width);
+    var tooltipWidth = parseFloat(_window2['default'].getComputedStyle(this.tooltip).width);
+    var tooltipWidthHalf = tooltipWidth / 2;
+    var actualPosition = position;
+
+    if (position < tooltipWidthHalf) {
+      actualPosition = Math.ceil(tooltipWidthHalf);
+    } else if (position > playerWidth - tooltipWidthHalf) {
+      actualPosition = Math.floor(playerWidth - tooltipWidthHalf);
+    }
+
+    return actualPosition;
+  };
+
+  return MouseTimeDisplay;
+}(_component2['default']);
+
+_component2['default'].registerComponent('MouseTimeDisplay', MouseTimeDisplay);
+exports['default'] = MouseTimeDisplay;
+
+},{"5":5,"80":80,"82":82,"83":83,"93":93,"98":98}],17:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+var _component = _dereq_(5);
+
+var _component2 = _interopRequireDefault(_component);
+
+var _fn = _dereq_(82);
+
+var Fn = _interopRequireWildcard(_fn);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _formatTime = _dereq_(83);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var _formatTime2 = _interopRequireDefault(_formatTime);
 
-var _buttonJs = _dereq_('../button.js');
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _buttonJs2 = _interopRequireDefault(_buttonJs);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _componentJs = _dereq_('../component.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-progress-bar.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
 
 /**
- * Toggle fullscreen video
+ * Shows play progress
  *
- * @extends Button
- * @class FullscreenToggle
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends Component
+ * @class PlayProgressBar
  */
+var PlayProgressBar = function (_Component) {
+  _inherits(PlayProgressBar, _Component);
 
-var FullscreenToggle = (function (_Button) {
-  _inherits(FullscreenToggle, _Button);
+  function PlayProgressBar(player, options) {
+    _classCallCheck(this, PlayProgressBar);
 
-  function FullscreenToggle(player, options) {
-    _classCallCheck(this, FullscreenToggle);
+    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
 
-    _Button.call(this, player, options);
-    this.on(player, 'fullscreenchange', this.handleFullscreenChange);
-  }
+    _this.updateDataAttr();
+    _this.on(player, 'timeupdate', _this.updateDataAttr);
+    player.ready(Fn.bind(_this, _this.updateDataAttr));
 
-  /**
-   * Allow sub components to stack CSS class names
-   *
-   * @return {String} The constructed class name
-   * @method buildCSSClass
-   */
+    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
+      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
+    }
 
-  FullscreenToggle.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-fullscreen-control ' + _Button.prototype.buildCSSClass.call(this);
-  };
+    if (_this.keepTooltipsInside) {
+      _this.addClass('vjs-keep-tooltips-inside');
+    }
+    return _this;
+  }
 
   /**
-   * Handles Fullscreenchange on the component and change control text accordingly
+   * Create the component's DOM element
    *
-   * @method handleFullscreenChange
+   * @return {Element}
+   * @method createEl
    */
 
-  FullscreenToggle.prototype.handleFullscreenChange = function handleFullscreenChange() {
-    if (this.player_.isFullscreen()) {
-      this.controlText('Non-Fullscreen');
-    } else {
-      this.controlText('Fullscreen');
-    }
+
+  PlayProgressBar.prototype.createEl = function createEl() {
+    return _Component.prototype.createEl.call(this, 'div', {
+      className: 'vjs-play-progress vjs-slider-bar',
+      innerHTML: '<span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>'
+    });
   };
 
-  /**
-   * Handles click for full screen
-   *
-   * @method handleClick
-   */
+  PlayProgressBar.prototype.updateDataAttr = function updateDataAttr() {
+    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
 
-  FullscreenToggle.prototype.handleClick = function handleClick() {
-    if (!this.player_.isFullscreen()) {
-      this.player_.requestFullscreen();
-    } else {
-      this.player_.exitFullscreen();
-    }
+    this.el_.setAttribute('data-current-time', (0, _formatTime2['default'])(time, this.player_.duration()));
   };
 
-  return FullscreenToggle;
-})(_buttonJs2['default']);
-
-FullscreenToggle.prototype.controlText_ = 'Fullscreen';
+  return PlayProgressBar;
+}(_component2['default']);
 
-_componentJs2['default'].registerComponent('FullscreenToggle', FullscreenToggle);
-exports['default'] = FullscreenToggle;
-module.exports = exports['default'];
+_component2['default'].registerComponent('PlayProgressBar', PlayProgressBar);
+exports['default'] = PlayProgressBar;
 
-},{"../button.js":64,"../component.js":67}],72:[function(_dereq_,module,exports){
-/**
- * @file live-display.js
- */
+},{"5":5,"82":82,"83":83}],18:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+var _component = _dereq_(5);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+var _component2 = _interopRequireDefault(_component);
+
+_dereq_(19);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+_dereq_(16);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _component = _dereq_('../component');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _component2 = _interopRequireDefault(_component);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _utilsDomJs = _dereq_('../utils/dom.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file progress-control.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var Dom = _interopRequireWildcard(_utilsDomJs);
 
 /**
- * Displays the live indicator
- * TODO - Future make it click to snap to live
+ * The Progress Control component contains the seek bar, load progress,
+ * and play progress
  *
+ * @param {Player|Object} player
+ * @param {Object=} options
  * @extends Component
- * @class LiveDisplay
+ * @class ProgressControl
  */
+var ProgressControl = function (_Component) {
+  _inherits(ProgressControl, _Component);
 
-var LiveDisplay = (function (_Component) {
-  _inherits(LiveDisplay, _Component);
-
-  function LiveDisplay(player, options) {
-    _classCallCheck(this, LiveDisplay);
-
-    _Component.call(this, player, options);
+  function ProgressControl() {
+    _classCallCheck(this, ProgressControl);
 
-    this.updateShowing();
-    this.on(this.player(), 'durationchange', this.updateShowing);
+    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
   }
 
   /**
@@ -5227,323 +3610,298 @@ var LiveDisplay = (function (_Component) {
    * @return {Element}
    * @method createEl
    */
-
-  LiveDisplay.prototype.createEl = function createEl() {
-    var el = _Component.prototype.createEl.call(this, 'div', {
-      className: 'vjs-live-control vjs-control'
-    });
-
-    this.contentEl_ = Dom.createEl('div', {
-      className: 'vjs-live-display',
-      innerHTML: '<span class="vjs-control-text">' + this.localize('Stream Type') + '</span>' + this.localize('LIVE')
-    }, {
-      'aria-live': 'off'
+  ProgressControl.prototype.createEl = function createEl() {
+    return _Component.prototype.createEl.call(this, 'div', {
+      className: 'vjs-progress-control vjs-control'
     });
-
-    el.appendChild(this.contentEl_);
-    return el;
   };
 
-  LiveDisplay.prototype.updateShowing = function updateShowing() {
-    if (this.player().duration() === Infinity) {
-      this.show();
-    } else {
-      this.hide();
-    }
-  };
+  return ProgressControl;
+}(_component2['default']);
 
-  return LiveDisplay;
-})(_component2['default']);
+ProgressControl.prototype.options_ = {
+  children: ['seekBar']
+};
 
-_component2['default'].registerComponent('LiveDisplay', LiveDisplay);
-exports['default'] = LiveDisplay;
-module.exports = exports['default'];
+_component2['default'].registerComponent('ProgressControl', ProgressControl);
+exports['default'] = ProgressControl;
 
-},{"../component":67,"../utils/dom.js":142}],73:[function(_dereq_,module,exports){
-/**
- * @file mute-toggle.js
- */
+},{"16":16,"19":19,"5":5}],19:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+var _window = _dereq_(93);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+var _window2 = _interopRequireDefault(_window);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _slider = _dereq_(57);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var _slider2 = _interopRequireDefault(_slider);
 
-var _button = _dereq_('../button');
+var _component = _dereq_(5);
 
-var _button2 = _interopRequireDefault(_button);
+var _component2 = _interopRequireDefault(_component);
 
-var _component = _dereq_('../component');
+var _fn = _dereq_(82);
 
-var _component2 = _interopRequireDefault(_component);
+var Fn = _interopRequireWildcard(_fn);
 
-var _utilsDomJs = _dereq_('../utils/dom.js');
+var _formatTime = _dereq_(83);
 
-var Dom = _interopRequireWildcard(_utilsDomJs);
+var _formatTime2 = _interopRequireDefault(_formatTime);
 
-/**
- * A button component for muting the audio
- *
- * @param {Player|Object} player
- * @param {Object=} options
- * @extends Button
- * @class MuteToggle
- */
+_dereq_(15);
 
-var MuteToggle = (function (_Button) {
-  _inherits(MuteToggle, _Button);
+_dereq_(17);
 
-  function MuteToggle(player, options) {
-    _classCallCheck(this, MuteToggle);
+_dereq_(20);
 
-    _Button.call(this, player, options);
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-    this.on(player, 'volumechange', this.update);
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-    // hide mute toggle if the current tech doesn't support volume control
-    if (player.tech_ && player.tech_['featuresVolumeControl'] === false) {
-      this.addClass('vjs-hidden');
-    }
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-    this.on(player, 'loadstart', function () {
-      this.update(); // We need to update the button to account for a default muted state.
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-      if (player.tech_['featuresVolumeControl'] === false) {
-        this.addClass('vjs-hidden');
-      } else {
-        this.removeClass('vjs-hidden');
-      }
-    });
-  }
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file seek-bar.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-  /**
-   * Allow sub components to stack CSS class names
-   *
-   * @return {String} The constructed class name
-   * @method buildCSSClass
-   */
 
-  MuteToggle.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-mute-control ' + _Button.prototype.buildCSSClass.call(this);
-  };
+/**
+ * Seek Bar and holder for the progress bars
+ *
+ * @param {Player|Object} player
+ * @param {Object=} options
+ * @extends Slider
+ * @class SeekBar
+ */
+var SeekBar = function (_Slider) {
+  _inherits(SeekBar, _Slider);
+
+  function SeekBar(player, options) {
+    _classCallCheck(this, SeekBar);
+
+    var _this = _possibleConstructorReturn(this, _Slider.call(this, player, options));
+
+    _this.on(player, 'timeupdate', _this.updateProgress);
+    _this.on(player, 'ended', _this.updateProgress);
+    player.ready(Fn.bind(_this, _this.updateProgress));
+
+    if (options.playerOptions && options.playerOptions.controlBar && options.playerOptions.controlBar.progressControl && options.playerOptions.controlBar.progressControl.keepTooltipsInside) {
+      _this.keepTooltipsInside = options.playerOptions.controlBar.progressControl.keepTooltipsInside;
+    }
+
+    if (_this.keepTooltipsInside) {
+      _this.tooltipProgressBar = _this.addChild('TooltipProgressBar');
+    }
+    return _this;
+  }
 
   /**
-   * Handle click on mute
+   * Create the component's DOM element
    *
-   * @method handleClick
+   * @return {Element}
+   * @method createEl
    */
 
-  MuteToggle.prototype.handleClick = function handleClick() {
-    this.player_.muted(this.player_.muted() ? false : true);
+
+  SeekBar.prototype.createEl = function createEl() {
+    return _Slider.prototype.createEl.call(this, 'div', {
+      className: 'vjs-progress-holder'
+    }, {
+      'aria-label': 'progress bar'
+    });
   };
 
   /**
-   * Update volume
+   * Update ARIA accessibility attributes
    *
-   * @method update
+   * @method updateARIAAttributes
    */
 
-  MuteToggle.prototype.update = function update() {
-    var vol = this.player_.volume(),
-        level = 3;
 
-    if (vol === 0 || this.player_.muted()) {
-      level = 0;
-    } else if (vol < 0.33) {
-      level = 1;
-    } else if (vol < 0.67) {
-      level = 2;
-    }
+  SeekBar.prototype.updateProgress = function updateProgress() {
+    this.updateAriaAttributes(this.el_);
 
-    // Don't rewrite the button text if the actual text doesn't change.
-    // This causes unnecessary and confusing information for screen reader users.
-    // This check is needed because this function gets called every time the volume level is changed.
-    var toMute = this.player_.muted() ? 'Unmute' : 'Mute';
-    if (this.controlText() !== toMute) {
-      this.controlText(toMute);
-    }
+    if (this.keepTooltipsInside) {
+      this.updateAriaAttributes(this.tooltipProgressBar.el_);
+      this.tooltipProgressBar.el_.style.width = this.bar.el_.style.width;
 
-    /* TODO improve muted icon classes */
-    for (var i = 0; i < 4; i++) {
-      Dom.removeElClass(this.el_, 'vjs-vol-' + i);
+      var playerWidth = parseFloat(_window2['default'].getComputedStyle(this.player().el()).width);
+      var tooltipWidth = parseFloat(_window2['default'].getComputedStyle(this.tooltipProgressBar.tooltip).width);
+      var tooltipStyle = this.tooltipProgressBar.el().style;
+
+      tooltipStyle.maxWidth = Math.floor(playerWidth - tooltipWidth / 2) + 'px';
+      tooltipStyle.minWidth = Math.ceil(tooltipWidth / 2) + 'px';
+      tooltipStyle.right = '-' + tooltipWidth / 2 + 'px';
     }
-    Dom.addElClass(this.el_, 'vjs-vol-' + level);
   };
 
-  return MuteToggle;
-})(_button2['default']);
-
-MuteToggle.prototype.controlText_ = 'Mute';
+  SeekBar.prototype.updateAriaAttributes = function updateAriaAttributes(el) {
+    // Allows for smooth scrubbing, when player can't keep up.
+    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
 
-_component2['default'].registerComponent('MuteToggle', MuteToggle);
-exports['default'] = MuteToggle;
-module.exports = exports['default'];
+    // machine readable value of progress bar (percentage complete)
+    el.setAttribute('aria-valuenow', (this.getPercent() * 100).toFixed(2));
+    // human readable value of progress bar (time complete)
+    el.setAttribute('aria-valuetext', (0, _formatTime2['default'])(time, this.player_.duration()));
+  };
 
-},{"../button":64,"../component":67,"../utils/dom.js":142}],74:[function(_dereq_,module,exports){
-/**
- * @file play-toggle.js
- */
-'use strict';
+  /**
+   * Get percentage of video played
+   *
+   * @return {Number} Percentage played
+   * @method getPercent
+   */
 
-exports.__esModule = true;
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+  SeekBar.prototype.getPercent = function getPercent() {
+    var percent = this.player_.currentTime() / this.player_.duration();
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+    return percent >= 1 ? 1 : percent;
+  };
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+  /**
+   * Handle mouse down on seek bar
+   *
+   * @method handleMouseDown
+   */
 
-var _buttonJs = _dereq_('../button.js');
 
-var _buttonJs2 = _interopRequireDefault(_buttonJs);
+  SeekBar.prototype.handleMouseDown = function handleMouseDown(event) {
+    _Slider.prototype.handleMouseDown.call(this, event);
 
-var _componentJs = _dereq_('../component.js');
+    this.player_.scrubbing(true);
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
+    this.videoWasPlaying = !this.player_.paused();
+    this.player_.pause();
+  };
 
-/**
- * Button to toggle between play and pause
- *
- * @param {Player|Object} player
- * @param {Object=} options
- * @extends Button
- * @class PlayToggle
- */
+  /**
+   * Handle mouse move on seek bar
+   *
+   * @method handleMouseMove
+   */
 
-var PlayToggle = (function (_Button) {
-  _inherits(PlayToggle, _Button);
 
-  function PlayToggle(player, options) {
-    _classCallCheck(this, PlayToggle);
+  SeekBar.prototype.handleMouseMove = function handleMouseMove(event) {
+    var newTime = this.calculateDistance(event) * this.player_.duration();
 
-    _Button.call(this, player, options);
+    // Don't let video end while scrubbing.
+    if (newTime === this.player_.duration()) {
+      newTime = newTime - 0.1;
+    }
 
-    this.on(player, 'play', this.handlePlay);
-    this.on(player, 'pause', this.handlePause);
-  }
+    // Set new time (tell player to seek to new time)
+    this.player_.currentTime(newTime);
+  };
 
   /**
-   * Allow sub components to stack CSS class names
+   * Handle mouse up on seek bar
    *
-   * @return {String} The constructed class name
-   * @method buildCSSClass
+   * @method handleMouseUp
    */
 
-  PlayToggle.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-play-control ' + _Button.prototype.buildCSSClass.call(this);
-  };
 
-  /**
-   * Handle click to toggle between play and pause
-   *
-   * @method handleClick
-   */
+  SeekBar.prototype.handleMouseUp = function handleMouseUp(event) {
+    _Slider.prototype.handleMouseUp.call(this, event);
 
-  PlayToggle.prototype.handleClick = function handleClick() {
-    if (this.player_.paused()) {
+    this.player_.scrubbing(false);
+    if (this.videoWasPlaying) {
       this.player_.play();
-    } else {
-      this.player_.pause();
     }
   };
 
   /**
-   * Add the vjs-playing class to the element so it can change appearance
+   * Move more quickly fast forward for keyboard-only users
    *
-   * @method handlePlay
+   * @method stepForward
    */
 
-  PlayToggle.prototype.handlePlay = function handlePlay() {
-    this.removeClass('vjs-paused');
-    this.addClass('vjs-playing');
-    this.controlText('Pause'); // change the button text to "Pause"
+
+  SeekBar.prototype.stepForward = function stepForward() {
+    // more quickly fast forward for keyboard-only users
+    this.player_.currentTime(this.player_.currentTime() + 5);
   };
 
   /**
-   * Add the vjs-paused class to the element so it can change appearance
+   * Move more quickly rewind for keyboard-only users
    *
-   * @method handlePause
+   * @method stepBack
    */
 
-  PlayToggle.prototype.handlePause = function handlePause() {
-    this.removeClass('vjs-playing');
-    this.addClass('vjs-paused');
-    this.controlText('Play'); // change the button text to "Play"
+
+  SeekBar.prototype.stepBack = function stepBack() {
+    // more quickly rewind for keyboard-only users
+    this.player_.currentTime(this.player_.currentTime() - 5);
   };
 
-  return PlayToggle;
-})(_buttonJs2['default']);
+  return SeekBar;
+}(_slider2['default']);
 
-PlayToggle.prototype.controlText_ = 'Play';
+SeekBar.prototype.options_ = {
+  children: ['loadProgressBar', 'mouseTimeDisplay', 'playProgressBar'],
+  barName: 'playProgressBar'
+};
 
-_componentJs2['default'].registerComponent('PlayToggle', PlayToggle);
-exports['default'] = PlayToggle;
-module.exports = exports['default'];
+SeekBar.prototype.playerEvent = 'timeupdate';
 
-},{"../button.js":64,"../component.js":67}],75:[function(_dereq_,module,exports){
-/**
- * @file playback-rate-menu-button.js
- */
+_component2['default'].registerComponent('SeekBar', SeekBar);
+exports['default'] = SeekBar;
+
+},{"15":15,"17":17,"20":20,"5":5,"57":57,"82":82,"83":83,"93":93}],20:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _component = _dereq_(5);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+var _component2 = _interopRequireDefault(_component);
 
-var _menuMenuButtonJs = _dereq_('../../menu/menu-button.js');
+var _fn = _dereq_(82);
 
-var _menuMenuButtonJs2 = _interopRequireDefault(_menuMenuButtonJs);
+var Fn = _interopRequireWildcard(_fn);
 
-var _menuMenuJs = _dereq_('../../menu/menu.js');
+var _formatTime = _dereq_(83);
 
-var _menuMenuJs2 = _interopRequireDefault(_menuMenuJs);
+var _formatTime2 = _interopRequireDefault(_formatTime);
 
-var _playbackRateMenuItemJs = _dereq_('./playback-rate-menu-item.js');
+function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
 
-var _playbackRateMenuItemJs2 = _interopRequireDefault(_playbackRateMenuItemJs);
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _componentJs = _dereq_('../../component.js');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _utilsDomJs = _dereq_('../../utils/dom.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file play-progress-bar.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var Dom = _interopRequireWildcard(_utilsDomJs);
 
 /**
- * The component for controlling the playback rate
+ * Shows play progress
  *
  * @param {Player|Object} player
  * @param {Object=} options
- * @extends MenuButton
- * @class PlaybackRateMenuButton
+ * @extends Component
+ * @class PlayProgressBar
  */
+var TooltipProgressBar = function (_Component) {
+  _inherits(TooltipProgressBar, _Component);
 
-var PlaybackRateMenuButton = (function (_MenuButton) {
-  _inherits(PlaybackRateMenuButton, _MenuButton);
-
-  function PlaybackRateMenuButton(player, options) {
-    _classCallCheck(this, PlaybackRateMenuButton);
-
-    _MenuButton.call(this, player, options);
+  function TooltipProgressBar(player, options) {
+    _classCallCheck(this, TooltipProgressBar);
 
-    this.updateVisibility();
-    this.updateLabel();
+    var _this = _possibleConstructorReturn(this, _Component.call(this, player, options));
 
-    this.on(player, 'loadstart', this.updateVisibility);
-    this.on(player, 'ratechange', this.updateLabel);
+    _this.updateDataAttr();
+    _this.on(player, 'timeupdate', _this.updateDataAttr);
+    player.ready(Fn.bind(_this, _this.updateDataAttr));
+    return _this;
   }
 
   /**
@@ -5553,1051 +3911,902 @@ var PlaybackRateMenuButton = (function (_MenuButton) {
    * @method createEl
    */
 
-  PlaybackRateMenuButton.prototype.createEl = function createEl() {
-    var el = _MenuButton.prototype.createEl.call(this);
 
-    this.labelEl_ = Dom.createEl('div', {
-      className: 'vjs-playback-rate-value',
-      innerHTML: 1.0
+  TooltipProgressBar.prototype.createEl = function createEl() {
+    var el = _Component.prototype.createEl.call(this, 'div', {
+      className: 'vjs-tooltip-progress-bar vjs-slider-bar',
+      innerHTML: '<div class="vjs-time-tooltip"></div>\n        <span class="vjs-control-text"><span>' + this.localize('Progress') + '</span>: 0%</span>'
     });
 
-    el.appendChild(this.labelEl_);
+    this.tooltip = el.querySelector('.vjs-time-tooltip');
 
     return el;
   };
 
-  /**
-   * Allow sub components to stack CSS class names
-   *
-   * @return {String} The constructed class name
-   * @method buildCSSClass
-   */
+  TooltipProgressBar.prototype.updateDataAttr = function updateDataAttr() {
+    var time = this.player_.scrubbing() ? this.player_.getCache().currentTime : this.player_.currentTime();
+    var formattedTime = (0, _formatTime2['default'])(time, this.player_.duration());
 
-  PlaybackRateMenuButton.prototype.buildCSSClass = function buildCSSClass() {
-    return 'vjs-playback-rate ' + _MenuButton.prototype.buildCSSClass.call(this);
+    this.el_.setAttribute('data-current-time', formattedTime);
+    this.tooltip.innerHTML = formattedTime;
   };
 
-  /**
-   * Create the playback rate menu
-   *
-   * @return {Menu} Menu object populated with items
-   * @method createMenu
-   */
+  return TooltipProgressBar;
+}(_component2['default']);
 
-  PlaybackRateMenuButton.prototype.createMenu = function createMenu() {
-    var menu = new _menuMenuJs2['default'](this.player());
-    var rates = this.playbackRates();
+_component2['default'].registerComponent('TooltipProgressBar', TooltipProgressBar);
+exports['default'] = TooltipProgressBar;
 
-    if (rates) {
-      for (var i = rates.length - 1; i >= 0; i--) {
-        menu.addChild(new _playbackRateMenuItemJs2['default'](this.player(), { 'rate': rates[i] + 'x' }));
-      }
-    }
+},{"5":5,"82":82,"83":83}],21:[function(_dereq_,module,exports){
+'use strict';
 
-    return menu;
-  };
+exports.__esModule = true;
 
-  /**
-   * Updates ARIA accessibility attributes
-   *
-   * @method updateARIAAttributes
-   */
+var _spacer = _dereq_(22);
 
-  PlaybackRateMenuButton.prototype.updateARIAAttributes = function updateARIAAttributes() {
-    // Current playback rate
-    this.el().setAttribute('aria-valuenow', this.player().playbackRate());
-  };
+var _spacer2 = _interopRequireDefault(_spacer);
 
-  /**
-   * Handle menu item click
-   *
-   * @method handleClick
-   */
+var _component = _dereq_(5);
 
-  PlaybackRateMenuButton.prototype.handleClick = function handleClick() {
-    // select next rate option
-    var currentRate = this.player().playbackRate();
-    var rates = this.playbackRates();
+var _component2 = _interopRequireDefault(_component);
 
-    // this will select first one if the last one currently selected
-    var newRate = rates[0];
-    for (var i = 0; i < rates.length; i++) {
-      if (rates[i] > currentRate) {
-        newRate = rates[i];
-        break;
-      }
-    }
-    this.player().playbackRate(newRate);
-  };
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-  /**
-   * Get possible playback rates
-   *
-   * @return {Array} Possible playback rates
-   * @method playbackRates
-   */
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-  PlaybackRateMenuButton.prototype.playbackRates = function playbackRates() {
-    return this.options_['playbackRates'] || this.options_.playerOptions && this.options_.playerOptions['playbackRates'];
-  };
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-  /**
-   * Get whether playback rates is supported by the tech
-   * and an array of playback rates exists
-   *
-   * @return {Boolean} Whether changing playback rate is supported
-   * @method playbackRateSupported
-   */
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file custom-control-spacer.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-  PlaybackRateMenuButton.prototype.playbackRateSupported = function playbackRateSupported() {
-    return this.player().tech_ && this.player().tech_['featuresPlaybackRate'] && this.playbackRates() && this.playbackRates().length > 0;
-  };
+
+/**
+ * Spacer specifically meant to be used as an insertion point for new plugins, etc.
+ *
+ * @extends Spacer
+ * @class CustomControlSpacer
+ */
+var CustomControlSpacer = function (_Spacer) {
+  _inherits(CustomControlSpacer, _Spacer);
+
+  function CustomControlSpacer() {
+    _classCallCheck(this, CustomControlSpacer);
+
+    return _possibleConstructorReturn(this, _Spacer.apply(this, arguments));
+  }
 
   /**
-   * Hide playback rate controls when they're no playback rate options to select
+   * Allow sub components to stack CSS class names
    *
-   * @method updateVisibility
+   * @return {String} The constructed class name
+   * @method buildCSSClass
    */
-
-  PlaybackRateMenuButton.prototype.updateVisibility = function updateVisibility() {
-    if (this.playbackRateSupported()) {
-      this.removeClass('vjs-hidden');
-    } else {
-      this.addClass('vjs-hidden');
-    }
+  CustomControlSpacer.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-custom-control-spacer ' + _Spacer.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Update button label when rate changed
+   * Create the component's DOM element
    *
-   * @method updateLabel
+   * @return {Element}
+   * @method createEl
    */
 
-  PlaybackRateMenuButton.prototype.updateLabel = function updateLabel() {
-    if (this.playbackRateSupported()) {
-      this.labelEl_.innerHTML = this.player().playbackRate() + 'x';
-    }
-  };
 
-  return PlaybackRateMenuButton;
-})(_menuMenuButtonJs2['default']);
+  CustomControlSpacer.prototype.createEl = function createEl() {
+    var el = _Spacer.prototype.createEl.call(this, {
+      className: this.buildCSSClass()
+    });
 
-PlaybackRateMenuButton.prototype.controlText_ = 'Playback Rate';
+    // No-flex/table-cell mode requires there be some content
+    // in the cell to fill the remaining space of the table.
+    el.innerHTML = '&nbsp;';
+    return el;
+  };
 
-_componentJs2['default'].registerComponent('PlaybackRateMenuButton', PlaybackRateMenuButton);
-exports['default'] = PlaybackRateMenuButton;
-module.exports = exports['default'];
+  return CustomControlSpacer;
+}(_spacer2['default']);
 
-},{"../../component.js":67,"../../menu/menu-button.js":109,"../../menu/menu.js":111,"../../utils/dom.js":142,"./playback-rate-menu-item.js":76}],76:[function(_dereq_,module,exports){
-/**
- * @file playback-rate-menu-item.js
- */
+_component2['default'].registerComponent('CustomControlSpacer', CustomControlSpacer);
+exports['default'] = CustomControlSpacer;
+
+},{"22":22,"5":5}],22:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+var _component = _dereq_(5);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _component2 = _interopRequireDefault(_component);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _menuMenuItemJs = _dereq_('../../menu/menu-item.js');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _menuMenuItemJs2 = _interopRequireDefault(_menuMenuItemJs);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _componentJs = _dereq_('../../component.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                * @file spacer.js
+                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                */
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
 
 /**
- * The specific menu item type for selecting a playback rate
+ * Just an empty spacer element that can be used as an append point for plugins, etc.
+ * Also can be used to create space between elements when necessary.
  *
- * @param {Player|Object} player
- * @param {Object=} options
- * @extends MenuItem
- * @class PlaybackRateMenuItem
+ * @extends Component
+ * @class Spacer
  */
+var Spacer = function (_Component) {
+  _inherits(Spacer, _Component);
 
-var PlaybackRateMenuItem = (function (_MenuItem) {
-  _inherits(PlaybackRateMenuItem, _MenuItem);
-
-  function PlaybackRateMenuItem(player, options) {
-    _classCallCheck(this, PlaybackRateMenuItem);
-
-    var label = options['rate'];
-    var rate = parseFloat(label, 10);
-
-    // Modify options for parent MenuItem class's init.
-    options['label'] = label;
-    options['selected'] = rate === 1;
-    _MenuItem.call(this, player, options);
-
-    this.label = label;
-    this.rate = rate;
+  function Spacer() {
+    _classCallCheck(this, Spacer);
 
-    this.on(player, 'ratechange', this.update);
+    return _possibleConstructorReturn(this, _Component.apply(this, arguments));
   }
 
   /**
-   * Handle click on menu item
+   * Allow sub components to stack CSS class names
    *
-   * @method handleClick
+   * @return {String} The constructed class name
+   * @method buildCSSClass
    */
-
-  PlaybackRateMenuItem.prototype.handleClick = function handleClick() {
-    _MenuItem.prototype.handleClick.call(this);
-    this.player().playbackRate(this.rate);
+  Spacer.prototype.buildCSSClass = function buildCSSClass() {
+    return 'vjs-spacer ' + _Component.prototype.buildCSSClass.call(this);
   };
 
   /**
-   * Update playback rate with selected rate
+   * Create the component's DOM element
    *
-   * @method update
+   * @return {Element}
+   * @method createEl
    */
 
-  PlaybackRateMenuItem.prototype.update = function update() {
-    this.selected(this.player().playbackRate() === this.rate);
+
+  Spacer.prototype.createEl = function createEl() {
+    return _Component.prototype.createEl.call(this, 'div', {
+      className: this.buildCSSClass()
+    });
   };
 
-  return PlaybackRateMenuItem;
-})(_menuMenuItemJs2['default']);
+  return Spacer;
+}(_component2['default']);
 
-PlaybackRateMenuItem.prototype.contentElType = 'button';
+_component2['default'].registerComponent('Spacer', Spacer);
 
-_componentJs2['default'].registerComponent('PlaybackRateMenuItem', PlaybackRateMenuItem);
-exports['default'] = PlaybackRateMenuItem;
-module.exports = exports['default'];
+exports['default'] = Spacer;
 
-},{"../../component.js":67,"../../menu/menu-item.js":110}],77:[function(_dereq_,module,exports){
-/**
- * @file load-progress-bar.js
- */
+},{"5":5}],23:[function(_dereq_,module,exports){
 'use strict';
 
 exports.__esModule = true;
 
-function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj['default'] = obj; return newObj; } }
+var _textTrackMenuItem = _dereq_(31);
 
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+var _textTrackMenuItem2 = _interopRequireDefault(_textTrackMenuItem);
+
+var _component = _dereq_(5);
 
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
+var _component2 = _interopRequireDefault(_component);
 
-function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
 
-var _componentJs = _dereq_('../../component.js');
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
-var _componentJs2 = _interopRequireDefault(_componentJs);
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
 
-var _utilsDomJs = _dereq_('../../utils/dom.js');
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
+      &