diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index a46ed1a8a70caca2205e3668531279e1f50aafda..a9428c4656d4195b4db2ca4b840479570f38b700 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -403,10 +403,117 @@ function file_field_formatter_info() {
       'label' => t('URL to file'),
       'field types' => array('file'),
     ),
+    'file_player' => array(
+      'label' => t('Media Player'),
+      'description' => t('Play this file within a Media Player.'),
+      'field types' => array('file', 'text'),
+      'settings' => array(
+        'template' => 'default',
+        'preload' => TRUE,
+        'autoplay' => FALSE,
+        'loop' => FALSE,
+        'width' => '100%',
+        'height' => '400px',
+        'volume' => 80,
+        'sources' => FALSE,
+        'debug' => FALSE
+      )
+    )
   );
 }
 
 /**
+ * Implements hook_field_formatter_settings_form
+ */
+function file_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $element = array();
+  if ($display['type'] == 'file_player') {
+
+    // Get the player information and templates.
+    $info = file_media_player_info();
+    $templates = array_keys($info['templates']);
+    $templates = array_combine($templates, $templates);
+
+    $element['template'] = array(
+      '#title' => t('Template'),
+      '#type' => 'select',
+      '#options' => $templates,
+      '#default_value' => $settings['template']
+    );
+
+    $element['preload'] = array(
+      '#title' => t('Preload'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['preload']
+    );
+
+    $element['autoplay'] = array(
+      '#title' => t('Autoplay'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['autoplay']
+    );
+
+    $element['loop'] = array(
+      '#title' => t('Loop'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['loop']
+    );
+
+    $element['width'] = array(
+      '#title' => t('Width'),
+      '#type' => 'textfield',
+      '#default_value' => $settings['width']
+    );
+
+    $element['height'] = array(
+      '#title' => t('Height'),
+      '#type' => 'textfield',
+      '#default_value' => $settings['height']
+    );
+
+    $element['volume'] = array(
+      '#title' => t('Initial Volume (0 - 100)'),
+      '#type' => 'textfield',
+      '#default_value' => $settings['volume']
+    );
+
+    $element['sources'] = array(
+      '#title' => t('Allow multiple sources'),
+      '#description' => t('Checking this will turn multiple instances of files into multiple sources within the media element.'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['sources']
+    );
+
+    $element['debug'] = array(
+      '#title' => t('Debug Mode'),
+      '#type' => 'checkbox',
+      '#default_value' => $settings['debug']
+    );
+  }
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary
+ */
+function file_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+  $summary = '';
+  if ($display['type'] == 'file_player') {
+    $header = array('Setting', 'Value');
+    $rows = array();
+    foreach ($settings as $name => $value) {
+      $rows[] = array($name, $value);
+    }
+    $summary = theme('table', array('header' => $header, 'rows' => $rows));
+  }
+  return $summary;
+}
+
+/**
  * Implements hook_field_widget_info().
  */
 function file_field_widget_info() {
@@ -1001,6 +1108,56 @@ function file_field_formatter_view($entity_type, $entity, $field, $instance, $la
         );
       }
       break;
+
+    case 'file_player':
+      // Get the display settings.
+      $settings = $display['settings'];
+
+      // Get the ID for this media player.
+      $id = 'player-' . drupal_clean_css_identifier($field['field_name']);
+
+      // If they wish to show all sources within a single media element.
+      if ($settings['sources']) {
+
+        // Get the media tag.
+        $mediatag = '';
+        foreach ($items as $delta => $item) {
+          if ($mediatag = file_get_media_type((object)$item)) {
+            break;
+          }
+        }
+
+        // If the mediatag exists, then theme the player.
+        if ($mediatag) {
+          $settings['id'] = $id;
+          $element[$delta] = array(
+            '#theme' => 'media_player',
+            '#tag' => $mediatag,
+            '#attributes' => file_player_get_attributes($settings),
+            '#settings' => $settings,
+            '#sources' => $items
+          );
+        }
+      }
+      else {
+
+        // Iterate through all the items.
+        foreach ($items as $delta => $item) {
+
+          // Get the media tag.
+          if ($mediatag = file_get_media_type((object)$item)) {
+            $settings['id'] = $id . '-' . $delta;
+            $element[$delta] = array(
+              '#theme' => 'media_player',
+              '#tag' => $mediatag,
+              '#attributes' => file_player_get_attributes($settings),
+              '#settings' => $settings,
+              '#sources' => array($item)
+            );
+          }
+        }
+      }
+      break;
   }
 
   return $element;
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index a2a5a8080f80f96b822db3da0c8265f685aa3770..979e82dd9bb4298363805541480e99de51104fce 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -86,7 +86,7 @@ function file_element_info() {
  * Implements hook_theme().
  */
 function file_theme() {
-  return array(
+  $themes = array(
     // file.module.
     'file_link' => array(
       'variables' => array('file' => NULL, 'icon_directory' => NULL),
@@ -111,10 +111,363 @@ function file_theme() {
     'file_upload_help' => array(
       'variables' => array('description' => NULL, 'upload_validators' => NULL),
     ),
+
+    // media player theme
+    'media_player' => array(
+      'render element' => 'element',
+    )
+  );
+
+  // Register the player templates
+  $info = file_get_player_info();
+  foreach ($info['templates'] as $name => $info) {
+    $themes['media_player_' . $name] = array(
+      'template' => 'media_player_' . $name,
+      'variables' => array('params' => NULL),
+      'path' => $info['path']
+    );
+  }
+
+  // Return the themes.
+  return $themes;
+}
+
+/**
+ * Implements hook_library_info().
+ */
+function file_library_info() {
+  $path = drupal_get_path('module', 'file') . '/player';
+  return array(
+    'mediaplayer' => array(
+      'title' => 'Media Player',
+      'version' => '0.1',
+      'js' => array(
+        $path . '/bin/minplayer.compressed.js' => array('group' => JS_LIBRARY)
+      ),
+      'dependencies' => array(
+        array('system', 'ui.slider')
+      )
+    ),
+    'mediaplayer_debug' => array(
+      'title' => 'Media Player (Debug Mode)',
+      'version' => '0.1',
+      'js' => array(
+        $path . '/src/minplayer.compatibility.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.flags.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.async.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.plugin.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.display.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.image.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.file.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.playLoader.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.players.base.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.players.html5.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.players.flash.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.players.minplayer.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.players.youtube.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.players.vimeo.js' => array('group' => JS_LIBRARY),
+        $path . '/src/minplayer.controller.js' => array('group' => JS_LIBRARY)
+      ),
+      'dependencies' => array(
+        array('system', 'ui.slider')
+      )
+    )
+  );
+}
+
+/**
+ * Returns all of the media player information.
+ */
+function file_get_player_info() {
+
+  // Implement hook_media_player_info
+  $cache = cache();
+  $info = $cache->get('media_player_info');
+  if ($info) {
+    return $info->data;
+  }
+  else {
+    // Invoke all media_player_info and then set the cache.
+    $player_info = module_invoke_all('media_player_info');
+    $cache->set('media_player_info', $player_info);
+    return $player_info;
+  }
+}
+
+/**
+ * Implements hook_media_player_info
+ */
+function file_media_player_info() {
+  $path = drupal_get_path('module', 'file') . '/player/templates';
+  return array(
+    'plugins' => array(),
+    'templates' => array(
+      'default' => array(
+        'path' => $path . '/default',
+        'js' => array(
+          $path . '/default/js/minplayer.playLoader.default.js' => array('group' => JS_DEFAULT),
+          $path . '/default/js/minplayer.controller.default.js' => array('group' => JS_DEFAULT),
+          $path . '/default/js/minplayer.default.js' => array('group' => JS_DEFAULT)
+        ),
+        'css' => array(
+          $path . '/default/css/media_player_default.css' => array('group' => CSS_DEFAULT)
+        )
+      )
+    )
+  );
+}
+
+/**
+ * Returns the player settings.
+ */
+function file_player_settings() {
+  return array(
+    "id" => 'player',
+    "controller" => 'default',
+    "template" => 'default',
+    "swfplayer" => '',
+    "wmode" => 'transparent',
+    "preload" => true,
+    "autoplay" => false,
+    "loop" => false,
+    "width" => '100%',
+    "height" => '400px',
+    "debug" => false,
+    "volume" => 80,
+    "files" => array(),
+    "file" => '',
+    "preview" => '',
+    "attributes" => array()
   );
 }
 
 /**
+ * Register a new media player in JavaScript.
+ */
+function file_register_player($settings, $attributes) {
+  $playerId = $settings['id'];
+  file_player_add_resources($settings['template'], $settings['debug']);
+  $attributes = drupal_json_encode($attributes);
+  $settings = array_intersect_key($settings, file_player_settings());
+  $settings = trim(drupal_json_encode($settings), '{}');
+  $swfplayer = url(drupal_get_path('module', 'file') . '/player/flash/minplayer.swf');
+  drupal_add_js("
+    jQuery(function() {
+      jQuery('#{$playerId}').minplayer({
+        id:'#{$playerId}',
+        attributes:{$attributes},
+        {$settings},
+        swfplayer:'{$swfplayer}'
+      });
+    });
+  ", 'inline');
+}
+
+/**
+ * Theme a media player.
+ */
+function theme_media_player($variables) {
+
+  // Get the element for this player.
+  if (isset($variables['element'])) {
+    $element = &$variables['element'];
+  }
+  else {
+    $element &$variables;
+  }
+
+  // Get the settings.
+  $settings = $element['#settings'];
+  $attributes = $element['#attributes'];
+
+  // Check to make sure there are sources.
+  if (empty($element['#sources'])) {
+    return 'No media sources provided';
+  }
+
+  // Set the value.
+  $element['#value'] = '';
+
+  // Iterate through each of the sources and create a source for that file.
+  foreach ($element['#sources'] as $delta => $file) {
+
+    // Make sure this is an object.
+    $file = (object)$file;
+
+    // Gets the source of this media.
+    if ($source = file_get_source($file)) {
+
+      // Get the source attributes.
+      $source_attributes = array('src' => $source);
+
+      // Add the sources to the #value of the media tag.
+      $element['#value'] .= theme('html_tag', array(
+        'element' => array(
+          '#tag' => 'source',
+          '#attributes' => $source_attributes
+        )
+      ));
+    }
+  }
+
+  // Add some variables that the template needs.
+  $variables['player'] = theme('html_tag', $variables);
+  $variables['settings'] = $settings;
+
+  // Register the media player in JavaScript.
+  file_register_player($settings, $attributes);
+
+  // Return the theme for our media player.
+  return theme('media_player_' . $settings['template'], $variables);
+}
+
+/**
+ * Returns the media source provided a field.
+ *
+ * @param object A Drupal file object.
+ */
+function file_get_source($file) {
+  if ($file) {
+    if (isset($file->uri)) {
+      return file_create_url($file->uri);
+    }
+    else if (!empty($file->value)) {
+      return $file->value;
+    }
+  }
+  return '';
+}
+
+/**
+ * Returns the extension provided a file object.
+ *
+ * @param object A Drupal file object.
+ * @return string The file extension.
+ */
+function file_get_extension($file) {
+
+  // Get the file source.
+  if ($source = file_get_source($file)) {
+    return drupal_strtolower(drupal_substr($source, strrpos($source, '.') + 1));
+  }
+
+  return '';
+}
+
+/**
+ * Return the media type provided a Drupal file object.
+ *
+ * @param object A Drupal file object.
+ * @return string 'video', 'audio', or '' if none.
+ */
+function file_get_media_type($file) {
+
+  // First try the filemime.
+  if (isset($file->filemime)) {
+    if (strpos($file->filemime, 'video/') === 0) {
+      return 'video';
+    }
+    if (strpos($file->filemime, 'audio/') === 0) {
+      return 'audio';
+    }
+  }
+
+  // Next try the extension.
+  if ($ext = file_get_extension($file)) {
+
+    // Determine if the extension is a "video" type.
+    if (in_array($ext, array('swf', 'mov', 'mp4', 'm4v', 'flv', 'f4v', 'ogg', 'ogv', '3g2', 'webm'))) {
+      return 'video';
+    }
+
+    // Determine if the extension is an "audio" type.
+    if (in_array($ext, array('mp3', 'oga', 'wav', 'aif', 'm4a', 'aac'))) {
+      return 'audio';
+    }
+  }
+
+  // Return video if value is set, nothing otherwise.
+  return !empty($file->value) ? 'video' : '';
+}
+
+/**
+ * Returns the settings for this video or audio element.
+ */
+function file_player_get_attributes($settings) {
+  $attributes = array();
+  $element_settings = array('preload', 'autoplay', 'loop');
+  foreach ($settings as $name => $value) {
+    if ($value && in_array($name, $element_settings)) {
+      $attributes[$name] = NULL;
+    }
+  }
+
+  // Set the ID, width and height.
+  $attributes['id'] = $settings['id'] . '-player';
+  $attributes['width'] = '100%';
+  $attributes['height'] = '100%';
+  return $attributes;
+}
+
+/**
+ * Adds the media player resources to the view.
+ */
+function file_player_add_resources($template, $debug) {
+  static $resources_added = FALSE, $template_added = array();
+
+  // Get the player information.
+  $info = file_get_player_info();
+
+  if (!$resources_added) {
+
+    // Add the media player library.
+    drupal_add_library('file', $debug ? 'mediaplayer_debug' : 'mediaplayer');
+
+    // Iterate through all the plugins...
+    foreach ($info['plugins'] as $plugin) {
+
+      // Include all of the css and js files.
+      if ($plugin['js']) {
+        foreach ($plugin['js'] as $file => $options) {
+          drupal_add_js($file, $options);
+        }
+      }
+      if ($plugin['css']) {
+        foreach ($plugin['css'] as $file => $options) {
+          drupal_add_css($file, $options);
+        }
+      }
+    }
+  }
+
+  // Get the templates...
+  $templates = $info['templates'];
+
+  // If this template exists, then...
+  if (!isset($template_added[$template]) && isset($templates[$template])) {
+
+    // Statically cache this so we won't add it again.
+    $template_added[$template] = TRUE;
+
+    // Store the template info.
+    $template = $templates[$template];
+
+    // Include all of the template files.
+    if ($template['js']) {
+      foreach ($template['js'] as $file => $options) {
+        drupal_add_js($file, $options);
+      }
+    }
+    if ($template['css']) {
+      foreach ($template['css'] as $file => $options) {
+        drupal_add_css($file, $options);
+      }
+    }
+  }
+}
+
+/**
  * Implements hook_file_download().
  *
  * This function takes an extra parameter $field_type so that it may
diff --git a/core/modules/file/player/README.md b/core/modules/file/player/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..63034555b62fbae8e252698d3e1e138fd89d40f7
--- /dev/null
+++ b/core/modules/file/player/README.md
@@ -0,0 +1,122 @@
+minPlayer - Because less IS more.
+===================================
+
+The goal of this project is to provide a slim, well documented, object oriented,
+plugin-based "core" media player in which other players and libraries can build
+on top of.  It is written using object oriented JavaScript and is continuously
+integrated using JSLint, JSDoc, and Google Closure.
+
+Multiple players - One single API.
+-----------------------------------
+It also allows for hot-swappable 3rd party API players by providing a common
+API for all of these players so that they can be utilized in the same manner.
+This means that once you develop for the minPlayer, one can easily bring in a
+different player an your code will still function as it would for all the
+others.  Out of the box, this player provides a common API for YouTube, Vimeo,
+HTML5, and Flash with more on the way.
+
+Everything is a plugin
+-----------------------------------
+Since this is a plugin-based media player, every displayable class must derive
+from the plugin class, thereby, making it a plugin.  This includes the media
+player itself.  This plugin system is highly flexible to be able to handle
+just about any type of plugin imaginable, and allows for every plugin to have
+direct dependeny-injected control over any other plugin within the media player.
+
+Complete User Interface & Business Logic separation
+-----------------------------------
+One common complaint for many media solutions out there is that they hijack the
+DOM and build out their own controls to provide consistency amongst different
+browsers.  They do this, however, within the core player which completely binds
+the user interface to the business logic of the media player.  The minPlayer
+takes a different approach by keeping ALL user interface functionality within
+the "templates" directory, where each template essentially derives from the base
+Business logic classes only to provide the user interface aspects of that control.
+This allows for easy templating of the media player besides just overriding the
+CSS like current media solutions do today.
+
+No "Features"!
+-----------------------------------
+I am pleased to say that this media player does NOT have many features, and this
+is on purpose.  Since this is a "core" player, it does not have any features
+other than what is critical in presenting your media.  Any additional "bling"
+will be added to this player from different repositories and from different
+players that extend this "core" functionality.  This methodology will keep this
+"core" media solution lean & highly functional.
+
+API
+-----------------------------------
+The API for minPlayer is very simple.  It revolves around a single API that is
+able to retrieve any plugin even before that plugin is created.  By doing this,
+you can have complete control over any plugin within the minPlayer.  This API
+is simply called
+
+```
+minplayer.get();
+```
+
+This API can take up to three different argument with each argument providing
+different usage.  The code docs for this function are as follows...
+
+```
+/**
+ * The main API for minPlayer.
+ *
+ * Provided that this function takes three parameters, there are 8 different
+ * ways to use this api.
+ *
+ *   id (0x100) - You want a specific player.
+ *   plugin (0x010) - You want a specific plugin.
+ *   callback (0x001) - You only want it when it is ready.
+ *
+ *   000 - You want all plugins from all players, ready or not.
+ *
+ *          var instances = minplayer.get();
+ *
+ *   001 - You want all plugins from all players, but only when ready.
+ *
+ *          minplayer.get(function(plugin) {
+ *            // Code goes here.
+ *          });
+ *
+ *   010 - You want a specific plugin from all players, ready or not...
+ *
+ *          var medias = minplayer.get(null, 'media');
+ *
+ *   011 - You want a specific plugin from all players, but only when ready.
+ *
+ *          minplayer.get('player', function(player) {
+ *            // Code goes here.
+ *          });
+ *
+ *   100 - You want all plugins from a specific player, ready or not.
+ *
+ *          var plugins = minplayer.get('player_id');
+ *
+ *   101 - You want all plugins from a specific player, but only when ready.
+ *
+ *          minplayer.get('player_id', null, function(plugin) {
+ *            // Code goes here.
+ *          });
+ *
+ *   110 - You want a specific plugin from a specific player, ready or not.
+ *
+ *          var plugin = minplayer.get('player_id', 'media');
+ *
+ *   111 - You want a specific plugin from a specific player, only when ready.
+ *
+ *          minplayer.get('player_id', 'media', function(media) {
+ *            // Code goes here.
+ *          });
+ *
+ * @this The context in which this function was called.
+ * @param {string} id The ID of the widget to get the plugins from.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the plugin is ready.
+ * @return {object} The plugin object if it is immediately available.
+ */
+minplayer.get = function(id, plugin, callback) {
+};
+```
+
+Thanks and enjoy minPlayer.
\ No newline at end of file
diff --git a/core/modules/file/player/bin/minplayer.compressed.js b/core/modules/file/player/bin/minplayer.compressed.js
new file mode 100644
index 0000000000000000000000000000000000000000..86b8f83a050def4af234f682149a2d8ec47ce833
--- /dev/null
+++ b/core/modules/file/player/bin/minplayer.compressed.js
@@ -0,0 +1,103 @@
+var minplayer=minplayer||{};function checkPlayType(a,b){if("function"===typeof a.canPlayType){if("object"===typeof b){for(var c=b.length,d="";c--&&!(d=checkPlayType(a,b[c])););return d}c=a.canPlayType(b);if("no"!==c&&""!==c)return b}return""}
+minplayer.compatibility=function(){var a=null,a=document.createElement("video");this.videoOGG=checkPlayType(a,"video/ogg");this.videoH264=checkPlayType(a,["video/mp4","video/h264"]);this.videoWEBM=checkPlayType(a,["video/x-webm","video/webm","application/octet-stream"]);a=document.createElement("audio");this.audioOGG=checkPlayType(a,"audio/ogg");this.audioMP3=checkPlayType(a,"audio/mpeg");this.audioMP4=checkPlayType(a,"audio/mp4")};minplayer.playTypes||(minplayer.playTypes=new minplayer.compatibility);
+minplayer=minplayer||{};minplayer.async=function(){this.value=null;this.queue=[]};minplayer.async.prototype.get=function(a){this.value!==null?a(this.value):this.queue.push(a)};minplayer.async.prototype.set=function(a){this.value=a;var b=this.queue.length;if(b){for(;b--;)this.queue[b](a);this.queue=[]}};minplayer=minplayer||{};minplayer.flags=function(){this.flag=0;this.ids={};this.numFlags=0};
+minplayer.flags.prototype.setFlag=function(a,b){if(!this.ids.hasOwnProperty(a)){this.ids[a]=this.numFlags;this.numFlags++}this.flag=b?this.flag|1<<this.ids[a]:this.flag&~(1<<this.ids[a])};minplayer=minplayer||{};minplayer.plugins=minplayer.plugins||{};minplayer.queue=minplayer.queue||[];minplayer.lock=!1;minplayer.plugin=function(a,b,c,d){this.name=a;this.pluginReady=false;this.options=c||{};this.queue=d||{};this.triggered={};this.lock=false;if(b){this.context=b;this.construct()}};
+minplayer.plugin.prototype.construct=function(){this.addPlugin()};minplayer.plugin.prototype.destroy=function(){this.unbind()};minplayer.plugin.prototype.create=function(a,b,c){var d=null,b=b||"minplayer",c=c||this.display;if(window[b][a]){d=window[b][a];d[this.options.template]&&(d=d[this.options.template]);return new d(c,this.options)}return null};minplayer.plugin.prototype.ready=function(){if(!this.pluginReady){this.pluginReady=true;this.trigger("ready");this.checkQueue()}};
+minplayer.plugin.prototype.addPlugin=function(a,b){a=a||this.name;b=b||this;if(b.isValid()){minplayer.plugins[this.options.id]||(minplayer.plugins[this.options.id]={});minplayer.plugins[this.options.id][a]=b}};minplayer.plugin.prototype.poll=function(a,b){setTimeout(function(c){return function e(){a.call(c)&&setTimeout(e,b)}}(this),b)};minplayer.plugin.prototype.get=function(a,b){if(typeof a==="function"){b=a;a=null}return minplayer.get.call(this,this.options.id,a,b)};
+minplayer.plugin.prototype.checkQueue=function(){var a=null,b=0,c=false,d=[];minplayer.lock=true;for(var e=minplayer.queue.length,b=0;b<e;b++){a=minplayer.queue[b];c=!a.id&&!a.plugin;(c=c|(a.plugin==this.name&&(!a.id||a.id==this.options.id)))&&(c=minplayer.bind.call(a.context,a.event,this.options.id,this.name,a.callback));c||d.push(a)}minplayer.queue=d;minplayer.lock=false};
+minplayer.plugin.prototype.trigger=function(a,b){b=b||{};b.plugin=this;this.triggered[a]=b;if(this.queue.hasOwnProperty(a)){var c=0,d={};for(c in this.queue[a]){d=this.queue[a][c];d.callback({target:this,data:d.data},b)}}return this};minplayer.plugin.prototype.bind=function(a,b,c){if(typeof b==="function"){c=b;b=null}if(a&&c){this.queue[a]=this.queue[a]||[];this.unbind(a,c);this.queue[a].push({callback:c,data:b});this.triggered[a]&&c({target:this,data:b},this.triggered[a]);return this}};
+minplayer.plugin.prototype.unbind=function(a,b){this.lock&&setTimeout(function(c){return function(){c.unbind(a,b)}}(this),10);this.lock=true;if(a)if(b){var c=0,d={};for(c in this.queue[a])if(this.queue[a][c].callback===b){d=this.queue[a].splice(1,1);delete d}}else this.queue[a]=[];else this.queue={};this.lock=false;return this};minplayer.addQueue=function(a,b,c,d,e){minplayer.lock?setTimeout(function(){minplayer.addQueue(a,c,b,d,e)},10):minplayer.queue.push({context:a,id:c,event:b,plugin:d,callback:e})};
+minplayer.bind=function(a,b,c,d){if(!d)return false;var e=minplayer.plugins;if(e[b][c]){e[b][c].bind(a,{context:this},function(a,b){d.call(a.data.context,b.plugin)});return true}minplayer.addQueue(this,a,b,c,d);return false};
+minplayer.get=function(a,b,c){if(typeof a==="function"){c=a;b=a=null}if(typeof b==="function"){c=b;b=a;a=null}var c=typeof c==="function"?c:null,d=minplayer.plugins;if(!a&&!b&&!c)return d;if(a&&!b&&!c)return d[a];if(a&&b&&!c)return d[a][b];if(a&&b&&c)minplayer.bind.call(this,"ready",a,b,c);else if(!a&&b&&c)for(a in d)minplayer.bind.call(this,"ready",a,b,c);else if(a&&!b&&c)for(b in d[a])minplayer.bind.call(this,"ready",a,b,c);else{if(!a&&b&&!c){c={};for(a in d)d.hasOwnProperty(a)&&d[a].hasOwnProperty(b)&&
+(c[a]=d[a][b]);return c}for(a in d)for(b in d[a])minplayer.bind.call(this,"ready",a,b,c)}};minplayer=minplayer||{};minplayer.display=function(a,b,c,d){this.allowResize=false;if(b)this.display=this.getDisplay(b,c);minplayer.plugin.call(this,a,b,c,d)};minplayer.display.prototype=new minplayer.plugin;minplayer.display.prototype.constructor=minplayer.display;minplayer.display.prototype.getDisplay=function(a){return jQuery(a)};
+minplayer.display.prototype.construct=function(){minplayer.plugin.prototype.construct.call(this);this.elements=this.getElements();if(this.allowResize){var a=0;jQuery(window).resize(function(b){return function(){clearTimeout(a);a=setTimeout(function(){b.onResize()},200)}}(this))}};minplayer.display.prototype.onResize=function(){};minplayer.display.prototype.fullScreenElement=function(){return this.display};
+minplayer.showThenHide=function(a,b){b=b||5E3;a.showTimer||jQuery(document).bind("mousemove",function(){minplayer.showThenHide(a,b)});clearTimeout(a.showTimer);a.show();a.showTimer=setTimeout(function(){a.hide("slow")},b)};
+minplayer.display.prototype.fullscreen=function(a){var b=this.isFullScreen(),c=this.fullScreenElement();if(b&&!a){c.removeClass("fullscreen");screenfull&&screenfull.exit();this.trigger("fullscreen",false)}else if(!b&&a){c.addClass("fullscreen");if(screenfull){screenfull.request(c[0]);screenfull.onchange=function(a){return function(){screenfull.isFullscreen||a.fullscreen(false)}}(this)}this.trigger("fullscreen",true)}};minplayer.display.prototype.toggleFullScreen=function(){this.fullscreen(!this.isFullScreen())};
+minplayer.display.prototype.isFullScreen=function(){return this.fullScreenElement().hasClass("fullscreen")};minplayer.display.prototype.getScaledRect=function(a,b){var c={};c.x=b.x?b.x:0;c.y=b.y?b.y:0;c.width=b.width?b.width:0;c.height=b.height?b.height:0;if(a){if(b.width/b.height>a){c.height=b.height;c.width=Math.floor(b.height*a)}else{c.height=Math.floor(b.width/a);c.width=b.width}c.x=Math.floor((b.width-c.width)/2);c.y=Math.floor((b.height-c.height)/2)}return c};
+minplayer.display.prototype.getElements=function(){return{}};minplayer.display.prototype.isValid=function(){return this.display.length>0};
+(function(a,b){var c=function(){for(var a=[["requestFullscreen","exitFullscreen","fullscreenchange","fullscreen","fullscreenElement"],["webkitRequestFullScreen","webkitCancelFullScreen","webkitfullscreenchange","webkitIsFullScreen","webkitCurrentFullScreenElement"],["mozRequestFullScreen","mozCancelFullScreen","mozfullscreenchange","mozFullScreen","mozFullScreenElement"]],c=0,d=a.length;c<d;c++){var e=a[c];if(e[1]in b)return e}}();if(!c)return a.screenfull=false;var d="ALLOW_KEYBOARD_INPUT"in Element,
+e={init:function(){b.addEventListener(c[2],function(a){e.isFullscreen=b[c[3]];e.element=b[c[4]];e.onchange(a)});return this},isFullscreen:b[c[3]],element:b[c[4]],request:function(a){a=a||b.documentElement;a[c[0]](d&&Element.ALLOW_KEYBOARD_INPUT);if(!b.isFullscreen)a[c[0]]()},exit:function(){b[c[1]]()},toggle:function(a){this.isFullscreen?this.exit():this.request(a)},onchange:function(){}};a.screenfull=e.init()})(window,document);
+jQuery.fn.minplayer||(jQuery.fn.minplayer=function(a){return jQuery(this).each(function(){a=a||{};a.id=a.id||$(this).attr("id")||Math.random();if(!minplayer.plugins[a.id]){a.template=a.template||"default";minplayer[a.template]?new minplayer[a.template](jQuery(this),a):new minplayer(jQuery(this),a)}})});minplayer=jQuery.extend(function(a,b){minplayer.display.call(this,"player",a,b)},minplayer);minplayer.prototype=new minplayer.display;minplayer.prototype.constructor=minplayer;
+minplayer.console=console||{log:function(){}};
+minplayer.prototype.construct=function(){jQuery.each(this.context[0].attributes,function(a){return function(b,c){a.options[c.name]=a.options[c.name]||c.value}}(this));this.options=jQuery.extend({id:"player",build:false,wmode:"transparent",preload:true,autoplay:false,loop:false,width:"100%",height:"350px",debug:false,volume:80,files:[],file:"",preview:"",attributes:{}},this.options);minplayer.display.prototype.construct.call(this);this.controller=this.create("controller");this.playLoader=this.create("playLoader");
+this.currentPlayer="html5";this.addKeyEvents();this.load(this.getFiles());this.addEvents();this.ready()};minplayer.prototype.addEvents=function(){minplayer.get.call(this,this.options.id,null,function(a){return function(b){b.bind("error",function(b,d){if(a.currentPlayer=="html5"){a.options.file.player="minplayer";a.loadPlayer()}else a.error(d)});b.bind("fullscreen",function(){a.resize()})}}(this))};
+minplayer.prototype.error=function(a){a=a||"";if(this.elements.error){this.elements.error.text(a);a?this.elements.error.show():this.elements.error.hide()}};minplayer.prototype.addKeyEvents=function(){jQuery(document).bind("keydown",function(a){return function(b){switch(b.keyCode){case 113:case 27:a.isFullScreen()&&a.fullscreen(false)}}}(this))};
+minplayer.prototype.getFiles=function(){var a=[],b=null;if(this.elements.media){(b=this.elements.media.attr("src"))&&a.push({path:b});jQuery("source",this.elements.media).each(function(){a.push({path:jQuery(this).attr("src"),mimetype:jQuery(this).attr("type"),codecs:jQuery(this).attr("codecs")})})}return a};
+minplayer.prototype.getMediaFile=function(a){if(!a)return null;if(typeof a==="string")return new minplayer.file({path:a});if(a.path||a.id)return new minplayer.file(a);for(var b=a.length,c=null,d=null;b--;){d=a[b];d=typeof d==="string"?new minplayer.file({path:d}):new minplayer.file(d);d.priority>0&&(c=d)}return c};
+minplayer.prototype.loadPlayer=function(){if(this.options.file)if(this.options.file.player){this.error();var a=this.options.file.player.toString();if(!this.media||a!==this.currentPlayer){this.currentPlayer=a;if(this.elements.display){a={};if(this.media){a=this.media.queue;this.media.destroy()}pClass=minplayer.players[this.options.file.player];this.options.mediaelement=this.elements.media;this.media=new pClass(this.elements.display,this.options,a);this.get("media",function(a){return function(c){c.load(a.options.file)}}(this))}else this.error("No media display found.")}else this.media&&
+this.media.load(this.options.file)}else this.error("Cannot play media: "+this.options.file.mimetype);else this.error("No media found.")};minplayer.prototype.load=function(a){this.options.files=a||this.options.files;this.options.file=this.getMediaFile(this.options.files);this.loadPlayer()};minplayer.prototype.resize=function(){this.get(function(a){a.onResize()})};minplayer=minplayer||{};
+minplayer.image=function(a,b){this.loaded=false;this.loader=null;this.ratio=0;this.img=null;minplayer.display.call(this,"image",a,b)};minplayer.image.prototype=new minplayer.display;minplayer.image.prototype.constructor=minplayer.image;
+minplayer.image.prototype.construct=function(){this.allowResize=true;minplayer.display.prototype.construct.call(this);this.display.css("overflow","hidden");this.loader=new Image;this.loader.onload=function(a){return function(){a.loaded=true;a.ratio=a.loader.width/a.loader.height;a.resize();a.trigger("loaded")}}(this);this.ready()};
+minplayer.image.prototype.load=function(a){this.clear(function(){this.display.empty();this.img=jQuery(document.createElement("img")).attr({src:""}).hide();this.display.append(this.img);this.loader.src=a})};minplayer.image.prototype.clear=function(a){this.loaded=false;this.img?this.img.fadeOut(function(b){return function(){b.img.attr("src","");b.loader.src="";$(this).remove();a.call(b)}}(this)):a.call(this)};
+minplayer.image.prototype.resize=function(a,b){a=a||this.display.width();b=b||this.display.height();if(a&&b&&this.loaded){var c=this.getScaledRect(this.ratio,{width:a,height:b});this.img&&this.img.attr("src",this.loader.src).css({marginLeft:c.x,marginTop:c.y,width:c.width,height:c.height});this.img.fadeIn()}};minplayer.image.prototype.onResize=function(){this.resize()};minplayer=minplayer||{};
+minplayer.file=function(a){this.duration=a.duration||0;this.bytesTotal=a.bytesTotal||0;this.quality=a.quality||0;this.stream=a.stream||"";this.path=a.path||"";this.codecs=a.codecs||"";this.extension=a.extension||this.getFileExtension();this.mimetype=a.mimetype||a.filemime||this.getMimeType();this.type=a.type||this.getType();if(!this.type){this.mimetype=this.getMimeType();this.type=this.getType()}this.player=a.player||this.getBestPlayer();this.priority=a.priority||this.getPriority();this.id=a.id||
+this.getId()};minplayer.file.prototype.getBestPlayer=function(){var a=null,b=0;jQuery.each(minplayer.players,function(c){return function(d,e){var f=e.getPriority();if(e.canPlay(c)&&f>b){a=d;b=f}}}(this));return a};
+minplayer.file.prototype.getPriority=function(){var a=1;this.player&&(a=minplayer.players[this.player].getPriority());switch(this.mimetype){case "video/x-webm":case "video/webm":case "application/octet-stream":return a*10;case "video/mp4":case "audio/mp4":case "audio/mpeg":return a*9;case "video/ogg":case "audio/ogg":case "video/quicktime":return a*8;default:return a*5}};minplayer.file.prototype.getFileExtension=function(){return this.path.substring(this.path.lastIndexOf(".")+1).toLowerCase()};
+minplayer.file.prototype.getMimeType=function(){switch(this.extension){case "mp4":case "m4v":case "flv":case "f4v":return"video/mp4";case "webm":return"video/webm";case "ogg":case "ogv":return"video/ogg";case "3g2":return"video/3gpp2";case "3gpp":case "3gp":return"video/3gpp";case "mov":return"video/quicktime";case "swf":return"application/x-shockwave-flash";case "oga":return"audio/ogg";case "mp3":return"audio/mpeg";case "m4a":case "f4a":return"audio/mp4";case "aac":return"audio/aac";case "wav":return"audio/vnd.wave";
+case "wma":return"audio/x-ms-wma";default:return"unknown"}};minplayer.file.prototype.getType=function(){switch(this.mimetype){case "video/mp4":case "video/webm":case "application/octet-stream":case "video/x-webm":case "video/ogg":case "video/3gpp2":case "video/3gpp":case "video/quicktime":return"video";case "audio/mp3":case "audio/mp4":case "audio/ogg":case "audio/mpeg":return"audio";default:return""}};
+minplayer.file.prototype.getId=function(){var a=minplayer.players[this.player];return a&&a.getMediaId?a.getMediaId(this):""};minplayer=minplayer||{};minplayer.playLoader=function(a,b){this.busy=new minplayer.flags;this.bigPlay=new minplayer.flags;this.preview=null;minplayer.display.call(this,"playLoader",a,b)};minplayer.playLoader.prototype=new minplayer.display;minplayer.playLoader.prototype.constructor=minplayer.playLoader;
+minplayer.playLoader.prototype.construct=function(){minplayer.display.prototype.construct.call(this);this.get("media",function(a){if(a.hasPlayLoader()){this.elements.busy&&this.elements.busy.unbind().hide();this.elements.bigPlay&&this.elements.bigPlay.unbind().hide();this.display.unbind().hide()}else{if(!this.options.preview)this.options.preview=a.elements.media.attr("poster");a.elements.media.attr("poster","");this.loadPreview();this.elements.bigPlay&&this.elements.bigPlay.unbind().bind("click",
+function(b){b.preventDefault();jQuery(this).hide();a.play()});a.unbind("loadstart").bind("loadstart",function(a){return function(){a.busy.setFlag("media",true);a.bigPlay.setFlag("media",true);a.preview&&a.elements.preview.show();a.checkVisibility()}}(this));a.bind("waiting",function(a){return function(){a.busy.setFlag("media",true);a.checkVisibility()}}(this));a.bind("loadeddata",function(a){return function(){a.busy.setFlag("media",false);a.checkVisibility()}}(this));a.bind("playing",function(a){return function(){a.busy.setFlag("media",
+false);a.bigPlay.setFlag("media",false);a.preview&&a.elements.preview.hide();a.checkVisibility()}}(this));a.bind("pause",function(a){return function(){a.bigPlay.setFlag("media",true);a.checkVisibility()}}(this))}});this.ready()};minplayer.playLoader.prototype.loadPreview=function(){if(this.elements.preview)if(this.options.preview){this.elements.preview.addClass("has-preview").show();this.preview=new minplayer.image(this.elements.preview,this.options);this.preview.load(this.options.preview)}else this.elements.preview.hide()};
+minplayer.playLoader.prototype.checkVisibility=function(){this.busy.flag?this.elements.busy.show():this.elements.busy.hide();this.bigPlay.flag?this.elements.bigPlay.show():this.elements.bigPlay.hide();(this.bigPlay.flag||this.busy.flag)&&this.display.show();!this.bigPlay.flag&&!this.busy.flag&&this.display.hide()};minplayer=minplayer||{};minplayer.players=minplayer.players||{};minplayer.players.base=function(a,b,c){minplayer.display.call(this,"media",a,b,c)};minplayer.players.base.prototype=new minplayer.display;
+minplayer.players.base.prototype.constructor=minplayer.players.base;minplayer.players.base.prototype.getElements=function(){var a=minplayer.display.prototype.getElements.call(this);return jQuery.extend(a,{media:this.options.mediaelement})};minplayer.players.base.getPriority=function(){return 0};minplayer.players.base.getMediaId=function(){return""};minplayer.players.base.canPlay=function(){return false};
+minplayer.players.base.prototype.construct=function(){minplayer.display.prototype.construct.call(this);this.clear();this.mediaFile=this.options.file;if(!this.playerFound()){this.elements.media&&this.elements.media.remove();this.elements.media=jQuery(this.create());this.display.html(this.elements.media)}this.player=this.getPlayer();jQuery(document).bind("click",function(a){return function(b){a.hasFocus=jQuery(b.target).closest("#"+a.options.id).length==0?false:true}}(this));jQuery(document).bind("keydown",
+function(a){return function(b){if(a.hasFocus){b.preventDefault();switch(b.keyCode){case 32:case 179:a.playing?a.pause():a.play();break;case 38:a.setVolumeRelative(0.1);break;case 40:a.setVolumeRelative(-0.1);break;case 37:case 227:a.seekRelative(-0.05);break;case 39:case 228:a.seekRelative(0.05)}}}}(this))};minplayer.players.base.prototype.destroy=function(){minplayer.plugin.prototype.destroy.call(this);this.clear()};
+minplayer.players.base.prototype.clear=function(){this.playerReady=false;this.reset();this.player&&jQuery(this.player).unbind()};
+minplayer.players.base.prototype.reset=function(){this.duration=new minplayer.async;this.currentTime=new minplayer.async;this.bytesLoaded=new minplayer.async;this.bytesTotal=new minplayer.async;this.bytesStart=new minplayer.async;this.volume=new minplayer.async;this.loading=this.playing=this.hasFocus=false;this.trigger("pause");this.trigger("waiting");this.trigger("progress",{loaded:0,total:0,start:0});this.trigger("timeupdate",{currentTime:0,duration:0})};
+minplayer.players.base.prototype.onReady=function(){if(!this.playerReady){this.playerReady=true;this.setVolume(this.options.volume/100);this.loading=true;this.poll(function(a){return function(){a.loading&&a.getBytesLoaded(function(b){a.getBytesTotal(function(c){if(b||c){var d=0;a.getBytesStart(function(a){d=a});a.trigger("progress",{loaded:b,total:c,start:d});if(b>=c)a.loading=false}})});return a.loading}}(this),1E3);this.ready();this.trigger("loadstart")}};
+minplayer.players.base.prototype.onPlaying=function(){this.trigger("playing");this.playing=this.hasFocus=true;this.poll(function(a){return function(){a.playing&&a.getCurrentTime(function(b){a.getDuration(function(c){b=parseFloat(b);c=parseFloat(c);(b||c)&&a.trigger("timeupdate",{currentTime:b,duration:c})})});return a.playing}}(this),1E3)};minplayer.players.base.prototype.onPaused=function(){this.trigger("pause");this.playing=this.hasFocus=false};
+minplayer.players.base.prototype.onComplete=function(){this.hasFocus=this.loading=this.playing=false;this.trigger("ended")};minplayer.players.base.prototype.onLoaded=function(){this.trigger("loadeddata")};minplayer.players.base.prototype.onWaiting=function(){this.trigger("waiting")};minplayer.players.base.prototype.onError=function(a){this.hasFocus=false;this.trigger("error",a)};minplayer.players.base.prototype.isReady=function(){return this.player&&this.playerReady};
+minplayer.players.base.prototype.hasPlayLoader=function(){return false};minplayer.players.base.prototype.playerFound=function(){return false};minplayer.players.base.prototype.create=function(){this.reset();return null};minplayer.players.base.prototype.getPlayer=function(){return this.player};minplayer.players.base.prototype.load=function(a){var b=typeof this.mediaFile=="string"?this.mediaFile:this.mediaFile.path;if(a&&a.path!=b){this.reset();this.mediaFile=a}};
+minplayer.players.base.prototype.play=function(){};minplayer.players.base.prototype.pause=function(){};minplayer.players.base.prototype.stop=function(){this.hasFocus=this.loading=this.playing=false};minplayer.players.base.prototype.seekRelative=function(a){this.getCurrentTime(function(b){return function(c){b.getDuration(function(d){if(d){var e=0,e=a>-1&&a<1?c/d+parseFloat(a):(c+parseFloat(a))/d;b.seek(e)}})}}(this))};minplayer.players.base.prototype.seek=function(){};
+minplayer.players.base.prototype.setVolumeRelative=function(a){this.getVolume(function(b){return function(c){c=c+parseFloat(a);c=c<0?0:c;b.setVolume(c>1?1:c)}}(this))};minplayer.players.base.prototype.setVolume=function(a){this.trigger("volumeupdate",a)};minplayer.players.base.prototype.getVolume=function(a){return this.volume.get(a)};minplayer.players.base.prototype.getCurrentTime=function(a){return this.currentTime.get(a)};minplayer.players.base.prototype.getDuration=function(a){return this.duration.get(a)};
+minplayer.players.base.prototype.getBytesStart=function(a){return this.bytesStart.get(a)};minplayer.players.base.prototype.getBytesLoaded=function(a){return this.bytesLoaded.get(a)};minplayer.players.base.prototype.getBytesTotal=function(a){return this.bytesTotal.get(a)};minplayer=minplayer||{};minplayer.players=minplayer.players||{};minplayer.players.html5=function(a,b,c){minplayer.players.base.call(this,a,b,c)};minplayer.players.html5.prototype=new minplayer.players.base;
+minplayer.players.html5.prototype.constructor=minplayer.players.html5;minplayer.players.html5.getPriority=function(){return 10};
+minplayer.players.html5.canPlay=function(a){switch(a.mimetype){case "video/ogg":return!!minplayer.playTypes.videoOGG;case "video/mp4":case "video/x-mp4":case "video/m4v":case "video/x-m4v":return!!minplayer.playTypes.videoH264;case "video/x-webm":case "video/webm":case "application/octet-stream":return!!minplayer.playTypes.videoWEBM;case "audio/ogg":return!!minplayer.playTypes.audioOGG;case "audio/mpeg":return!!minplayer.playTypes.audioMP3;case "audio/mp4":return!!minplayer.playTypes.audioMP4;default:return false}};
+minplayer.players.html5.prototype.construct=function(){minplayer.players.base.prototype.construct.call(this);if(this.player){this.player.addEventListener("abort",function(a){return function(){a.trigger("abort")}}(this),false);this.player.addEventListener("loadstart",function(a){return function(){a.onReady()}}(this),false);this.player.addEventListener("loadeddata",function(a){return function(){a.onLoaded()}}(this),false);this.player.addEventListener("loadedmetadata",function(a){return function(){a.onLoaded()}}(this),
+false);this.player.addEventListener("canplaythrough",function(a){return function(){a.onLoaded()}}(this),false);this.player.addEventListener("ended",function(a){return function(){a.onComplete()}}(this),false);this.player.addEventListener("pause",function(a){return function(){a.onPaused()}}(this),false);this.player.addEventListener("play",function(a){return function(){a.onPlaying()}}(this),false);this.player.addEventListener("playing",function(a){return function(){a.onPlaying()}}(this),false);this.player.addEventListener("error",
+function(a){return function(){a.trigger("error","An error occured - "+this.error.code)}}(this),false);this.player.addEventListener("waiting",function(a){return function(){a.onWaiting()}}(this),false);this.player.addEventListener("durationchange",function(a){return function(){a.duration.set(this.duration);a.trigger("durationchange",{duration:this.duration})}}(this),false);this.player.addEventListener("progress",function(a){return function(b){a.bytesTotal.set(b.total);a.bytesLoaded.set(b.loaded)}}(this),
+false);this.onReady()}};minplayer.players.html5.prototype.playerFound=function(){return this.display.find(this.mediaFile.type).length>0};minplayer.players.html5.prototype.create=function(){minplayer.players.base.prototype.create.call(this);var a=jQuery(document.createElement(this.mediaFile.type)).attr(this.options.attributes).append(jQuery(document.createElement("source")).attr({src:this.mediaFile.path}));a.eq(0)[0].setAttribute("width","100%");a.eq(0)[0].setAttribute("height","100%");return a};
+minplayer.players.html5.prototype.getPlayer=function(){return this.elements.media.eq(0)[0]};minplayer.players.html5.prototype.load=function(a){if(a){var b=this.elements.media.attr("src");b||(b=jQuery("source",this.elements.media).eq(0).attr("src"));if(b!=a.path){b='<source src="'+a.path+'">';this.elements.media.removeAttr("src").empty().html(b)}}minplayer.players.base.prototype.load.call(this,a)};
+minplayer.players.html5.prototype.play=function(){minplayer.players.base.prototype.play.call(this);this.isReady()&&this.player.play()};minplayer.players.html5.prototype.pause=function(){minplayer.players.base.prototype.pause.call(this);this.isReady()&&this.player.pause()};minplayer.players.html5.prototype.stop=function(){minplayer.players.base.prototype.stop.call(this);if(this.isReady()){this.player.pause();this.player.src=""}};
+minplayer.players.html5.prototype.seek=function(a){minplayer.players.base.prototype.seek.call(this,a);if(this.isReady())this.player.currentTime=a};minplayer.players.html5.prototype.setVolume=function(a){minplayer.players.base.prototype.setVolume.call(this,a);if(this.isReady())this.player.volume=a};minplayer.players.html5.prototype.getVolume=function(a){this.isReady()&&a(this.player.volume)};minplayer.players.html5.prototype.getDuration=function(a){this.isReady()&&a(this.player.duration)};
+minplayer.players.html5.prototype.getCurrentTime=function(a){this.isReady()&&a(this.player.currentTime)};
+minplayer.players.html5.prototype.getBytesLoaded=function(a){if(this.isReady()){var b=0;if(this.bytesLoaded.value)b=this.bytesLoaded.value;else if(this.player.buffered&&this.player.buffered.length>0&&this.player.buffered.end&&this.player.duration)b=this.player.buffered.end(0);else if(this.player.bytesTotal!=void 0&&this.player.bytesTotal>0&&this.player.bufferedBytes!=void 0)b=this.player.bufferedBytes;a(b)}};
+minplayer.players.html5.prototype.getBytesTotal=function(a){if(this.isReady()){var b=0;if(this.bytesTotal.value)b=this.bytesTotal.value;else if(this.player.buffered&&this.player.buffered.length>0&&this.player.buffered.end&&this.player.duration)b=this.player.duration;else if(this.player.bytesTotal!=void 0&&this.player.bytesTotal>0&&this.player.bufferedBytes!=void 0)b=this.player.bytesTotal;a(b)}};minplayer=minplayer||{};minplayer.players=minplayer.players||{};
+minplayer.players.flash=function(a,b,c){minplayer.players.base.call(this,a,b,c)};minplayer.players.flash.prototype=new minplayer.players.base;minplayer.players.flash.prototype.constructor=minplayer.players.flash;minplayer.players.flash.getPriority=function(){return 0};minplayer.players.flash.canPlay=function(){return false};
+minplayer.players.flash.getFlash=function(a){var b=window.location.protocol;b.charAt(b.length-1)==":"&&(b=b.substring(0,b.length-1));var c=jQuery.param(a.flashvars),d;d='<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '+('codebase="'+(b+"://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0")+'" ')+'playerType="flash" '+('width="'+a.width+'" ');d=d+('height="'+a.height+'" ');d=d+('id="'+a.id+'" ');d=d+('name="'+a.id+'"> ');d=d+'<param name="allowScriptAccess" value="always"></param><param name="allowfullscreen" value="true" />'+
+('<param name="movie" value="'+a.swf+'"></param>');d=d+('<param name="wmode" value="'+a.wmode+'"></param>');d=d+'<param name="quality" value="high"></param>'+('<param name="FlashVars" value="'+c+'"></param>')+('<embed src="'+a.swf+'" ');d=d+'quality="high" '+('width="'+a.width+'" height="'+a.height+'" ');d=d+('id="'+a.id+'" name="'+a.id+'" ');d=d+'swLiveConnect="true" allowScriptAccess="always" '+('wmode="'+a.wmode+'"');return d+'allowfullscreen="true" type="application/x-shockwave-flash" '+('FlashVars="'+
+c+'" ')+('pluginspage="'+b)+'://www.macromedia.com/go/getflashplayer" /></object>'};minplayer.players.flash.prototype.playerFound=function(){return this.display.find('object[playerType="flash"]').length>0};minplayer.players.flash.prototype.getPlayer=function(){return jQuery(jQuery.browser.msie?"object":"embed",this.display).eq(0)[0]};minplayer=minplayer||{};minplayer.players=minplayer.players||{};minplayer.players.minplayer=function(a,b,c){minplayer.players.flash.call(this,a,b,c)};
+minplayer.players.minplayer.prototype=new minplayer.players.flash;minplayer.players.minplayer.prototype.constructor=minplayer.players.minplayer;window.onFlashPlayerReady=function(a){if(a=minplayer.get(a,"media"))a.onReady()};window.onFlashPlayerUpdate=function(a,b){var c=minplayer.get(a,"media");if(c)c.onMediaUpdate(b)};window.onFlashPlayerDebug=function(a){minplayer.console.log(a)};minplayer.players.minplayer.getPriority=function(){return 1};
+minplayer.players.minplayer.canPlay=function(a){switch(a.mimetype){case "video/mp4":case "video/x-mp4":case "video/m4v":case "video/x-m4v":case "video/x-webm":case "video/webm":case "application/octet-stream":case "video/quicktime":case "video/3gpp2":case "video/3gpp":case "application/x-shockwave-flash":case "audio/mpeg":case "audio/mp4":case "audio/aac":case "audio/vnd.wave":case "audio/x-ms-wma":return true;default:return false}};
+minplayer.players.minplayer.prototype.create=function(){this.options=jQuery.extend({swfplayer:"flash/minplayer.swf"},this.options);minplayer.players.flash.prototype.create.call(this);return minplayer.players.flash.getFlash({swf:this.options.swfplayer,id:this.options.id+"_player",width:this.options.width,height:"100%",flashvars:{id:this.options.id,debug:this.options.debug,config:"nocontrols",file:this.mediaFile.path,autostart:this.options.autoplay},wmode:this.options.wmode})};
+minplayer.players.minplayer.prototype.onMediaUpdate=function(a){switch(a){case "mediaMeta":this.onLoaded();break;case "mediaPlaying":this.onPlaying();break;case "mediaPaused":this.onPaused();break;case "mediaComplete":this.onComplete()}};minplayer.players.minplayer.prototype.load=function(a){minplayer.players.flash.prototype.load.call(this,a);a&&this.isReady()&&this.player.loadMedia(a.path,a.stream)};
+minplayer.players.minplayer.prototype.play=function(){minplayer.players.flash.prototype.play.call(this);this.isReady()&&this.player.playMedia()};minplayer.players.minplayer.prototype.pause=function(){minplayer.players.flash.prototype.pause.call(this);this.isReady()&&this.player.pauseMedia()};minplayer.players.minplayer.prototype.stop=function(){minplayer.players.flash.prototype.stop.call(this);this.isReady()&&this.player.stopMedia()};
+minplayer.players.minplayer.prototype.seek=function(a){minplayer.players.flash.prototype.seek.call(this,a);this.isReady()&&this.player.seekMedia(a)};minplayer.players.minplayer.prototype.setVolume=function(a){minplayer.players.flash.prototype.setVolume.call(this,a);this.isReady()&&this.player.setVolume(a)};minplayer.players.minplayer.prototype.getVolume=function(a){this.isReady()&&a(this.player.getVolume())};
+minplayer.players.minplayer.prototype.getDuration=function(a){if(this.isReady()){var b=this.player.getDuration();b?a(b):this.poll(function(c){return function(){(b=c.player.getDuration())&&a(b);return!b}}(this),1E3)}};minplayer.players.minplayer.prototype.getCurrentTime=function(a){this.isReady()&&a(this.player.getCurrentTime())};minplayer.players.minplayer.prototype.getBytesLoaded=function(a){this.isReady()&&a(this.player.getMediaBytesLoaded())};
+minplayer.players.minplayer.prototype.getBytesTotal=function(a){this.isReady()&&a(this.player.getMediaBytesTotal())};minplayer=minplayer||{};minplayer.players=minplayer.players||{};minplayer.players.youtube=function(a,b,c){this.quality="default";minplayer.players.base.call(this,a,b,c)};minplayer.players.youtube.prototype=new minplayer.players.base;minplayer.players.youtube.prototype.constructor=minplayer.players.youtube;minplayer.players.youtube.getPriority=function(){return 10};
+minplayer.players.youtube.canPlay=function(a){return a.mimetype==="video/youtube"?true:a.path.search(/^http(s)?\:\/\/(www\.)?youtube\.com/i)===0};minplayer.players.youtube.getMediaId=function(a){var b=/^http[s]?\:\/\/(www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9]+)/i;return a.path.search(b)===0?a.path.match(b)[2]:a.path};
+minplayer.players.youtube.prototype.register=function(){window.onYouTubePlayerAPIReady=function(){jQuery.each(minplayer.get(null,"player"),function(a,b){if(b.currentPlayer=="youtube")b.media.player=new YT.Player(a+"-player",{events:{onReady:function(a){b.media.onReady(a)},onStateChange:function(a){b.media.onPlayerStateChange(a)},onPlaybackQualityChange:function(a){b.media.onQualityChange(a)},onError:function(a){b.media.onError(a)}}})})}};
+minplayer.players.youtube.prototype.setPlayerState=function(a){switch(a){case YT.PlayerState.BUFFERING:this.onWaiting();break;case YT.PlayerState.PAUSED:this.onPaused();break;case YT.PlayerState.PLAYING:this.onPlaying();break;case YT.PlayerState.ENDED:this.onComplete()}};minplayer.players.youtube.prototype.onReady=function(){minplayer.players.base.prototype.onReady.call(this);this.onLoaded()};
+minplayer.players.youtube.prototype.playerFound=function(){return this.display.find("iframe#"+this.options.id+"-player").length>0};minplayer.players.youtube.prototype.onPlayerStateChange=function(a){this.setPlayerState(a.data)};minplayer.players.youtube.prototype.onQualityChange=function(a){this.quality=a.data};minplayer.players.youtube.prototype.hasPlayLoader=function(){return true};
+minplayer.players.youtube.prototype.create=function(){minplayer.players.base.prototype.create.call(this);var a=document.createElement("script");a.src="http://www.youtube.com/player_api?enablejsapi=1";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);this.register();a=document.createElement("iframe");a.setAttribute("id",this.options.id+"-player");a.setAttribute("type","text/html");a.setAttribute("width","100%");a.setAttribute("height","100%");a.setAttribute("frameborder",
+"0");var b="http://www.youtube.com/embed/"+(this.mediaFile.id+"?"),c=location.protocol,c=c+("//"+location.hostname),c=c+(location.port&&":"+location.port),b=b+jQuery.param({wmode:"opaque",controls:0,enablejsapi:1,origin:c,autoplay:this.options.autoplay,loop:this.options.loop});a.setAttribute("src",b);return a};minplayer.players.youtube.prototype.load=function(a){minplayer.players.base.prototype.load.call(this,a);a&&this.isReady()&&this.player.loadVideoById(a.id,0,this.quality)};
+minplayer.players.youtube.prototype.play=function(){minplayer.players.base.prototype.play.call(this);this.isReady()&&this.player.playVideo()};minplayer.players.youtube.prototype.pause=function(){minplayer.players.base.prototype.pause.call(this);this.isReady()&&this.player.pauseVideo()};minplayer.players.youtube.prototype.stop=function(){minplayer.players.base.prototype.stop.call(this);this.isReady()&&this.player.stopVideo()};
+minplayer.players.youtube.prototype.seek=function(a){minplayer.players.base.prototype.seek.call(this,a);this.isReady()&&this.player.seekTo(a,true)};minplayer.players.youtube.prototype.setVolume=function(a){minplayer.players.base.prototype.setVolume.call(this,a);this.isReady()&&this.player.setVolume(a*100)};minplayer.players.youtube.prototype.getVolume=function(a){this.isReady()&&a(this.player.getVolume())};minplayer.players.youtube.prototype.getDuration=function(a){this.isReady()&&a(this.player.getDuration())};
+minplayer.players.youtube.prototype.getCurrentTime=function(a){this.isReady()&&a(this.player.getCurrentTime())};minplayer.players.youtube.prototype.getBytesStart=function(a){this.isReady()&&a(this.player.getVideoStartBytes())};minplayer.players.youtube.prototype.getBytesLoaded=function(a){this.isReady()&&a(this.player.getVideoBytesLoaded())};minplayer.players.youtube.prototype.getBytesTotal=function(a){this.isReady()&&a(this.player.getVideoBytesTotal())};minplayer=minplayer||{};
+minplayer.players=minplayer.players||{};minplayer.players.vimeo=function(a,b,c){minplayer.players.base.call(this,a,b,c)};minplayer.players.vimeo.prototype=new minplayer.players.base;minplayer.players.vimeo.prototype.constructor=minplayer.players.vimeo;minplayer.players.vimeo.getPriority=function(){return 10};minplayer.players.vimeo.canPlay=function(a){return a.mimetype==="video/vimeo"?true:a.path.search(/^http(s)?\:\/\/(www\.)?vimeo\.com/i)===0};
+minplayer.players.vimeo.getMediaId=function(a){var b=/^http[s]?\:\/\/(www\.)?vimeo\.com\/(\?v\=)?([0-9]+)/i;return a.path.search(b)===0?a.path.match(b)[3]:a.path};minplayer.players.vimeo.prototype.reset=function(){minplayer.players.base.prototype.reset.call(this)};
+minplayer.players.vimeo.prototype.create=function(){minplayer.players.base.prototype.create.call(this);var a=document.createElement("script");a.src="http://a.vimeocdn.com/js/froogaloop2.min.js";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);var c=document.createElement("iframe");c.setAttribute("id",this.options.id+"-player");c.setAttribute("type","text/html");c.setAttribute("width","100%");c.setAttribute("height","100%");c.setAttribute("frameborder","0");a="http://player.vimeo.com/video/"+
+(this.mediaFile.id+"?");a=a+jQuery.param({wmode:"opaque",api:1,player_id:this.options.id+"-player",title:0,byline:0,portrait:0,autoplay:this.options.autoplay,loop:this.options.loop});c.setAttribute("src",a);this.poll(function(a){return function(){if(window.Froogaloop){a.player=window.Froogaloop(c);a.player.addEvent("ready",function(){a.onReady()})}return!window.Froogaloop}}(this),200);this.trigger("loadstart");return c};
+minplayer.players.vimeo.prototype.onReady=function(){this.player.addEvent("loadProgress",function(a){return function(b){a.duration.set(parseFloat(b.duration));a.bytesLoaded.set(b.bytesLoaded);a.bytesTotal.set(b.bytesTotal)}}(this));this.player.addEvent("playProgress",function(a){return function(b){a.duration.set(parseFloat(b.duration));a.currentTime.set(parseFloat(b.seconds))}}(this));this.player.addEvent("play",function(a){return function(){a.onPlaying()}}(this));this.player.addEvent("pause",function(a){return function(){a.onPaused()}}(this));
+this.player.addEvent("finish",function(a){return function(){a.onComplete()}}(this));minplayer.players.base.prototype.onReady.call(this);this.onLoaded()};minplayer.players.vimeo.prototype.playerFound=function(){return this.display.find("iframe#"+this.options.id+"-player").length>0};minplayer.players.vimeo.prototype.play=function(){minplayer.players.base.prototype.play.call(this);this.isReady()&&this.player.api("play")};
+minplayer.players.vimeo.prototype.pause=function(){minplayer.players.base.prototype.pause.call(this);this.isReady()&&this.player.api("pause")};minplayer.players.vimeo.prototype.stop=function(){minplayer.players.base.prototype.stop.call(this);this.isReady()&&this.player.api("unload")};minplayer.players.vimeo.prototype.seek=function(a){minplayer.players.base.prototype.seek.call(this,a);this.isReady()&&this.player.api("seekTo",a)};
+minplayer.players.vimeo.prototype.setVolume=function(a){minplayer.players.base.prototype.setVolume.call(this,a);if(this.isReady()){this.volume.set(a);this.player.api("setVolume",a)}};minplayer.players.vimeo.prototype.getVolume=function(a){this.player.api("getVolume",function(b){a(b)})};minplayer.players.vimeo.prototype.getDuration=function(a){this.isReady()&&(this.duration.value?a(this.duration.value):this.player.api("getDuration",function(b){a(b)}))};minplayer=minplayer||{};
+minplayer.controller=function(a,b){minplayer.display.call(this,"controller",a,b)};minplayer.controller.prototype=new minplayer.display;minplayer.controller.prototype.constructor=minplayer.controller;minplayer.formatTime=function(a){var a=a||0,b=0,c=0,d=0,e="",d=Math.floor(a/3600),a=a-d*3600,c=Math.floor(a/60),b=Math.floor((a-c*60)%60);d&&(e=e+(""+d)+":");return{time:e+(c>=10?""+c:"0"+c)+":"+(b>=10?""+b:"0"+b),units:""}};
+minplayer.controller.prototype.getElements=function(){var a=minplayer.display.prototype.getElements.call(this);return jQuery.extend(a,{play:null,pause:null,fullscreen:null,seek:null,progress:null,volume:null,timer:null})};
+minplayer.controller.prototype.construct=function(){minplayer.display.prototype.construct.call(this);this.dragging=false;if(this.elements.seek)this.seekBar=this.elements.seek.slider({range:"min"});if(this.elements.volume)this.volumeBar=this.elements.volume.slider({range:"min",orientation:"vertical"});this.get("player",function(a){this.elements.fullscreen&&this.elements.fullscreen.unbind().bind("click",function(){a.toggleFullScreen()}).css({pointer:"hand"})});this.get("media",function(a){if(this.elements.pause){this.elements.pause.unbind().bind("click",
+function(b){return function(c){c.preventDefault();b.playPause(false,a)}}(this));a.bind("pause",function(a){return function(){a.setPlayPause(true)}}(this))}if(this.elements.play){this.elements.play.unbind().bind("click",function(b){return function(c){c.preventDefault();b.playPause(true,a)}}(this));a.bind("playing",function(a){return function(){a.setPlayPause(false)}}(this))}if(this.elements.duration){a.bind("durationchange",function(a){return function(c,d){a.setTimeString("duration",d.duration)}}(this));
+a.getDuration(function(a){return function(c){a.setTimeString("duration",c)}}(this))}this.elements.progress&&a.bind("progress",function(a){return function(c,d){a.elements.progress.width((d.total?d.loaded/d.total*100:0)+"%")}}(this));(this.seekBar||this.elements.timer)&&a.bind("timeupdate",function(a){return function(c,d){if(!a.dragging){var e=0;d.duration&&(e=d.currentTime/d.duration*100);a.seekBar&&a.seekBar.slider("option","value",e);a.setTimeString("timer",d.currentTime)}}}(this));this.seekBar&&
+this.seekBar.slider({start:function(a){return function(){a.dragging=true}}(this),stop:function(b){return function(c,d){b.dragging=false;a.getDuration(function(b){a.seek(d.value/100*b)})}}(this),slide:function(b){return function(c,d){a.getDuration(function(c){c=d.value/100*c;b.dragging||a.seek(c);b.setTimeString("timer",c)})}}(this)});if(this.volumeBar){this.volumeBar.slider({slide:function(b,c){a.setVolume(c.value/100)}});a.bind("volumeupdate",function(a){return function(c,d){a.volumeBar.slider("option",
+"value",d*100)}}(this));a.getVolume(function(a){return function(c){a.volumeBar.slider("option","value",c*100)}}(this))}});this.ready()};minplayer.controller.prototype.setPlayPause=function(a){this.elements.play&&this.elements.play.css("display",a?"inherit":"none");this.elements.pause&&this.elements.pause.css("display",a?"none":"inherit")};minplayer.controller.prototype.playPause=function(a,b){var c=a?"play":"pause";this.display.trigger(c);this.setPlayPause(!a);if(b)b[c]()};
+minplayer.controller.prototype.setTimeString=function(a,b){this.elements[a]&&this.elements[a].text(minplayer.formatTime(b).time)};
diff --git a/core/modules/file/player/bin/minplayer.js b/core/modules/file/player/bin/minplayer.js
new file mode 100644
index 0000000000000000000000000000000000000000..16950e289ab5591798ea8740a508d324a6abda56
--- /dev/null
+++ b/core/modules/file/player/bin/minplayer.js
@@ -0,0 +1,4167 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+// Private function to check a single element's play type.
+function checkPlayType(elem, playType) {
+  if ((typeof elem.canPlayType) === 'function') {
+    if (typeof playType === 'object') {
+      var i = playType.length;
+      var mimetype = '';
+      while (i--) {
+        mimetype = checkPlayType(elem, playType[i]);
+        if (!!mimetype) {
+          break;
+        }
+      }
+      return mimetype;
+    }
+    else {
+      var canPlay = elem.canPlayType(playType);
+      if (('no' !== canPlay) && ('' !== canPlay)) {
+        return playType;
+      }
+    }
+  }
+  return '';
+}
+
+/**
+ * @constructor
+ * @class This class is used to define the types of media that can be played
+ * within the browser.
+ * <p>
+ * <strong>Usage:</strong>
+ * <pre><code>
+ *   var playTypes = new minplayer.compatibility();
+ *
+ *   if (playTypes.videoOGG) {
+ *     console.log("This browser can play OGG video");
+ *   }
+ *
+ *   if (playTypes.videoH264) {
+ *     console.log("This browser can play H264 video");
+ *   }
+ *
+ *   if (playTypes.videoWEBM) {
+ *     console.log("This browser can play WebM video");
+ *   }
+ *
+ *   if (playTypes.audioOGG) {
+ *     console.log("This browser can play OGG audio");
+ *   }
+ *
+ *   if (playTypes.audioMP3) {
+ *     console.log("This browser can play MP3 audio");
+ *   }
+ *
+ *   if (playTypes.audioMP4) {
+ *     console.log("This browser can play MP4 audio");
+ *   }
+ * </code></pre>
+ */
+minplayer.compatibility = function() {
+  var elem = null;
+
+  // Create a video element.
+  elem = document.createElement('video');
+
+  /** Can play OGG video */
+  this.videoOGG = checkPlayType(elem, 'video/ogg');
+
+  /** Can play H264 video */
+  this.videoH264 = checkPlayType(elem, [
+    'video/mp4',
+    'video/h264'
+  ]);
+
+  /** Can play WEBM video */
+  this.videoWEBM = checkPlayType(elem, [
+    'video/x-webm',
+    'video/webm',
+    'application/octet-stream'
+  ]);
+
+  // Create an audio element.
+  elem = document.createElement('audio');
+
+  /** Can play audio OGG */
+  this.audioOGG = checkPlayType(elem, 'audio/ogg');
+
+  /** Can play audio MP3 */
+  this.audioMP3 = checkPlayType(elem, 'audio/mpeg');
+
+  /** Can play audio MP4 */
+  this.audioMP4 = checkPlayType(elem, 'audio/mp4');
+};
+
+if (!minplayer.playTypes) {
+
+  /** The compatible playtypes for this browser. */
+  minplayer.playTypes = new minplayer.compatibility();
+}
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class This class keeps track of asynchronous get requests for certain
+ * variables within the player.
+ */
+minplayer.async = function() {
+
+  /** The final value of this asynchronous variable. */
+  this.value = null;
+
+  /** The queue of callbacks to call when this value is determined. */
+  this.queue = [];
+};
+
+/**
+ * Retrieve the value of this variable.
+ *
+ * @param {function} callback The function to call when the value is determined.
+ * @param {function} pollValue The poll function to try and get the value every
+ * 1 second if the value is not set.
+ */
+minplayer.async.prototype.get = function(callback, pollValue) {
+
+  // If the value is set, then immediately call the callback, otherwise, just
+  // add it to the queue when the variable is set.
+  if (this.value !== null) {
+    callback(this.value);
+  }
+  else {
+
+    // Add this callback to the queue.
+    this.queue.push(callback);
+  }
+};
+
+/**
+ * Sets the value of an asynchronous value.
+ *
+ * @param {void} val The value to set.
+ */
+minplayer.async.prototype.set = function(val) {
+
+  // Set the value.
+  this.value = val;
+
+  // Get the callback queue length.
+  var i = this.queue.length;
+
+  // Iterate through all the callbacks and call them.
+  if (i) {
+    while (i--) {
+      this.queue[i](val);
+    }
+
+    // Reset the queue.
+    this.queue = [];
+  }
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class This is a class used to keep track of flag states
+ * which is used to control the busy cursor, big play button, among other
+ * items in which multiple components can have an interest in hiding or
+ * showing a single element on the screen.
+ *
+ * <p>
+ * <strong>Usage:</strong>
+ * <pre><code>
+ *   // Declare a flags variable.
+ *   var flags = new minplayer.flags();
+ *
+ *   // Set the flag based on two components interested in the flag.
+ *   flags.setFlag("component1", true);
+ *   flags.setFlag("component2", true);
+ *
+ *   // Print out the value of the flags. ( Prints 3 )
+ *   console.log(flags.flags);
+ *
+ *   // Now unset a single components flag.
+ *   flags.setFlag("component1", false);
+ *
+ *   // Print out the value of the flags.
+ *   console.log(flags.flags);
+ *
+ *   // Unset the other components flag.
+ *   flags.setFlag("component2", false);
+ *
+ *   // Print out the value of the flags.
+ *   console.log(flags.flags);
+ * </code></pre>
+ * </p>
+ */
+minplayer.flags = function() {
+
+  /** The flag. */
+  this.flag = 0;
+
+  /** Id map to reference id with the flag index. */
+  this.ids = {};
+
+  /** The number of flags. */
+  this.numFlags = 0;
+};
+
+/**
+ * Sets a flag based on boolean logic operators.
+ *
+ * @param {string} id The id of the controller interested in this flag.
+ * @param {boolean} value The value of this flag ( true or false ).
+ */
+minplayer.flags.prototype.setFlag = function(id, value) {
+
+  // Define this id if it isn't present.
+  if (!this.ids.hasOwnProperty(id)) {
+    this.ids[id] = this.numFlags;
+    this.numFlags++;
+  }
+
+  // Use binary operations to keep track of the flag state
+  if (value) {
+    this.flag |= (1 << this.ids[id]);
+  }
+  else {
+    this.flag &= ~(1 << this.ids[id]);
+  }
+};
+/** The minplayer namespace. */
+minplayer = minplayer || {};
+
+/** Static array to keep track of all plugins. */
+minplayer.plugins = minplayer.plugins || {};
+
+/** Static array to keep track of queues. */
+minplayer.queue = minplayer.queue || [];
+
+/** Mutex lock to keep multiple triggers from occuring. */
+minplayer.lock = false;
+
+/**
+ * @constructor
+ * @class The base class for all plugins.
+ *
+ * @param {string} name The name of this plugin.
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.plugin = function(name, context, options, queue) {
+
+  /** The name of this plugin. */
+  this.name = name;
+
+  /** The ready flag. */
+  this.pluginReady = false;
+
+  /** The options for this plugin. */
+  this.options = options || {};
+
+  /** The event queue. */
+  this.queue = queue || {};
+
+  /** Keep track of already triggered events. */
+  this.triggered = {};
+
+  /** Create a queue lock. */
+  this.lock = false;
+
+  // Only call the constructor if we have a context.
+  if (context) {
+
+    /** Keep track of the context. */
+    this.context = context;
+
+    // Construct this plugin.
+    this.construct();
+  }
+};
+
+/**
+ * The constructor which is called once the context is set.
+ * Any class deriving from the plugin class should place all context
+ * dependant functionality within this function instead of the standard
+ * constructor function since it is called on object derivation as well
+ * as object creation.
+ */
+minplayer.plugin.prototype.construct = function() {
+
+  // Adds this as a plugin.
+  this.addPlugin();
+};
+
+/**
+ * Destructor.
+ */
+minplayer.plugin.prototype.destroy = function() {
+
+  // Unbind all events.
+  this.unbind();
+};
+
+/**
+ * Creates a new plugin within this context.
+ *
+ * @param {string} name The name of the plugin you wish to create.
+ * @param {object} base The base object for this plugin.
+ * @param {object} context The context which you would like to create.
+ * @return {object} The new plugin object.
+ */
+minplayer.plugin.prototype.create = function(name, base, context) {
+  var plugin = null;
+
+  // Make sure we have a base object.
+  base = base || 'minplayer';
+
+  // Make sure there is a context.
+  context = context || this.display;
+
+  // See if this plugin exists within this object.
+  if (window[base][name]) {
+
+    // Set the plugin.
+    plugin = window[base][name];
+
+    // See if a template version of the plugin exists.
+    if (plugin[this.options.template]) {
+
+      plugin = plugin[this.options.template];
+    }
+
+    // Create the new plugin.
+    return new plugin(context, this.options);
+  }
+
+  return null;
+};
+
+/**
+ * Plugins should call this method when they are ready.
+ */
+minplayer.plugin.prototype.ready = function() {
+
+  // Keep this plugin from triggering multiple ready events.
+  if (!this.pluginReady) {
+
+    // Set the ready flag.
+    this.pluginReady = true;
+
+    // Now trigger that I am ready.
+    this.trigger('ready');
+
+    // Check the queue.
+    this.checkQueue();
+  }
+};
+
+/**
+ * Adds a new plugin to this player.
+ *
+ * @param {string} name The name of this plugin.
+ * @param {object} plugin A new plugin object, derived from media.plugin.
+ */
+minplayer.plugin.prototype.addPlugin = function(name, plugin) {
+  name = name || this.name;
+  plugin = plugin || this;
+
+  // Make sure the plugin is valid.
+  if (plugin.isValid()) {
+
+    // If the plugins for this instance do not exist.
+    if (!minplayer.plugins[this.options.id]) {
+
+      // Initialize the plugins.
+      minplayer.plugins[this.options.id] = {};
+    }
+
+    // Add this plugin.
+    minplayer.plugins[this.options.id][name] = plugin;
+  }
+};
+
+/**
+ * Create a polling timer.
+ *
+ * @param {function} callback The function to call when you poll.
+ * @param {integer} interval The interval you would like to poll.
+ */
+minplayer.plugin.prototype.poll = function(callback, interval) {
+  setTimeout((function(context) {
+    return function callLater() {
+      if (callback.call(context)) {
+        setTimeout(callLater, interval);
+      }
+    };
+  })(this), interval);
+};
+
+/**
+ * Gets a plugin by name and calls callback when it is ready.
+ *
+ * @param {string} plugin The plugin of the plugin.
+ * @param {function} callback Called when the plugin is ready.
+ * @return {object} The plugin if no callback is provided.
+ */
+minplayer.plugin.prototype.get = function(plugin, callback) {
+
+  // If they pass just a callback, then return all plugins when ready.
+  if (typeof plugin === 'function') {
+    callback = plugin;
+    plugin = null;
+  }
+
+  // Return the minplayer.get equivalent.
+  return minplayer.get.call(this, this.options.id, plugin, callback);
+};
+
+/**
+ * Check the queue and execute it.
+ */
+minplayer.plugin.prototype.checkQueue = function() {
+
+  // Initialize our variables.
+  var q = null, i = 0, check = false, newqueue = [];
+
+  // Set the lock.
+  minplayer.lock = true;
+
+  // Iterate through all the queues.
+  var length = minplayer.queue.length;
+  for (i = 0; i < length; i++) {
+
+    // Get the queue.
+    q = minplayer.queue[i];
+
+    // Now check to see if this queue is about us.
+    check = !q.id && !q.plugin;
+    check |= (q.plugin == this.name) && (!q.id || (q.id == this.options.id));
+
+    // If the check passes...
+    if (check) {
+      check = minplayer.bind.call(
+        q.context,
+        q.event,
+        this.options.id,
+        this.name,
+        q.callback
+      );
+    }
+
+    // Add the queue back if it doesn't check out.
+    if (!check) {
+
+      // Add this back to the queue.
+      newqueue.push(q);
+    }
+  }
+
+  // Set the old queue to the new queue.
+  minplayer.queue = newqueue;
+
+  // Release the lock.
+  minplayer.lock = false;
+};
+
+/**
+ * Trigger a media event.
+ *
+ * @param {string} type The event type.
+ * @param {object} data The event data object.
+ * @return {object} The plugin object.
+ */
+minplayer.plugin.prototype.trigger = function(type, data) {
+  data = data || {};
+  data.plugin = this;
+
+  // Add this to our triggered array.
+  this.triggered[type] = data;
+
+  // Check to make sure the queue for this type exists.
+  if (this.queue.hasOwnProperty(type)) {
+
+    var i = 0, queue = {};
+
+    // Iterate through all the callbacks in this queue.
+    for (i in this.queue[type]) {
+
+      // Setup the event object, and call the callback.
+      queue = this.queue[type][i];
+      queue.callback({target: this, data: queue.data}, data);
+    }
+  }
+
+  // Return the plugin object.
+  return this;
+};
+
+/**
+ * Bind to a media event.
+ *
+ * @param {string} type The event type.
+ * @param {object} data The data to bind with the event.
+ * @param {function} fn The callback function.
+ * @return {object} The plugin object.
+ **/
+minplayer.plugin.prototype.bind = function(type, data, fn) {
+
+  // Allow the data to be the callback.
+  if (typeof data === 'function') {
+    fn = data;
+    data = null;
+  }
+
+  // You must bind to a specific event and have a callback.
+  if (!type || !fn) {
+    return;
+  }
+
+  // Initialize the queue for this type.
+  this.queue[type] = this.queue[type] || [];
+
+  // Unbind any existing equivalent events.
+  this.unbind(type, fn);
+
+  // Now add this event to the queue.
+  this.queue[type].push({
+    callback: fn,
+    data: data
+  });
+
+  // Now see if this event has already been triggered.
+  if (this.triggered[type]) {
+
+    // Go ahead and trigger the event.
+    fn({target: this, data: data}, this.triggered[type]);
+  }
+
+  // Return the plugin.
+  return this;
+};
+
+/**
+ * Unbind a media event.
+ *
+ * @param {string} type The event type.
+ * @param {function} fn The callback function.
+ * @return {object} The plugin object.
+ **/
+minplayer.plugin.prototype.unbind = function(type, fn) {
+
+  // If this is locked then try again after 10ms.
+  if (this.lock) {
+    setTimeout((function(plugin) {
+      return function() {
+        plugin.unbind(type, fn);
+      };
+    })(this), 10);
+  }
+
+  // Set the lock.
+  this.lock = true;
+
+  if (!type) {
+    this.queue = {};
+  }
+  else if (!fn) {
+    this.queue[type] = [];
+  }
+  else {
+    // Iterate through all the callbacks and search for equal callbacks.
+    var i = 0, queue = {};
+    for (i in this.queue[type]) {
+      if (this.queue[type][i].callback === fn) {
+        queue = this.queue[type].splice(1, 1);
+        delete queue;
+      }
+    }
+  }
+
+  // Reset the lock.
+  this.lock = false;
+
+  // Return the plugin.
+  return this;
+};
+
+/**
+ * Adds an item to the queue.
+ *
+ * @param {object} context The context which this is called within.
+ * @param {string} event The event to trigger on.
+ * @param {string} id The player ID.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the event occurs.
+ */
+minplayer.addQueue = function(context, event, id, plugin, callback) {
+
+  // See if it is locked...
+  if (!minplayer.lock) {
+    minplayer.queue.push({
+      context: context,
+      id: id,
+      event: event,
+      plugin: plugin,
+      callback: callback
+    });
+  }
+  else {
+
+    // If so, then try again after 10 milliseconds.
+    setTimeout(function() {
+      minplayer.addQueue(context, id, event, plugin, callback);
+    }, 10);
+  }
+};
+
+/**
+ * Binds an event to a plugin instance, and if it doesn't exist, then caches
+ * it for a later time.
+ *
+ * @param {string} event The event to trigger on.
+ * @param {string} id The player ID.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the event occurs.
+ * @return {boolean} If the bind was successful.
+ * @this The object in context who called this method.
+ */
+minplayer.bind = function(event, id, plugin, callback) {
+
+  // If no callback exists, then just return false.
+  if (!callback) {
+    return false;
+  }
+
+  // Get the plugins.
+  var inst = minplayer.plugins;
+
+  // See if this plugin exists.
+  if (inst[id][plugin]) {
+
+    // If so, then bind the event to this plugin.
+    inst[id][plugin].bind(event, {context: this}, function(event, data) {
+      callback.call(event.data.context, data.plugin);
+    });
+    return true;
+  }
+
+  // If not, then add it to the queue to bind later.
+  minplayer.addQueue(this, event, id, plugin, callback);
+
+  // Return that this wasn't handled.
+  return false;
+};
+
+/**
+ * The main API for minPlayer.
+ *
+ * Provided that this function takes three parameters, there are 8 different
+ * ways to use this api.
+ *
+ *   id (0x100) - You want a specific player.
+ *   plugin (0x010) - You want a specific plugin.
+ *   callback (0x001) - You only want it when it is ready.
+ *
+ *   000 - You want all plugins from all players, ready or not.
+ *
+ *          var plugins = minplayer.get();
+ *
+ *   001 - You want all plugins from all players, but only when ready.
+ *
+ *          minplayer.get(function(plugin) {
+ *            // Code goes here.
+ *          });
+ *
+ *   010 - You want a specific plugin from all players, ready or not...
+ *
+ *          var medias = minplayer.get(null, 'media');
+ *
+ *   011 - You want a specific plugin from all players, but only when ready.
+ *
+ *          minplayer.get('player', function(player) {
+ *            // Code goes here.
+ *          });
+ *
+ *   100 - You want all plugins from a specific player, ready or not.
+ *
+ *          var plugins = minplayer.get('player_id');
+ *
+ *   101 - You want all plugins from a specific player, but only when ready.
+ *
+ *          minplayer.get('player_id', null, function(plugin) {
+ *            // Code goes here.
+ *          });
+ *
+ *   110 - You want a specific plugin from a specific player, ready or not.
+ *
+ *          var plugin = minplayer.get('player_id', 'media');
+ *
+ *   111 - You want a specific plugin from a specific player, only when ready.
+ *
+ *          minplayer.get('player_id', 'media', function(media) {
+ *            // Code goes here.
+ *          });
+ *
+ * @this The context in which this function was called.
+ * @param {string} id The ID of the widget to get the plugins from.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the plugin is ready.
+ * @return {object} The plugin object if it is immediately available.
+ */
+minplayer.get = function(id, plugin, callback) {
+
+  // Normalize the arguments for a better interface.
+  if (typeof id === 'function') {
+    callback = id;
+    plugin = id = null;
+  }
+
+  if (typeof plugin === 'function') {
+    callback = plugin;
+    plugin = id;
+    id = null;
+  }
+
+  // Make sure the callback is a callback.
+  callback = (typeof callback === 'function') ? callback : null;
+
+  // Get the plugins.
+  var plugins = minplayer.plugins;
+
+  // 0x000
+  if (!id && !plugin && !callback) {
+    return plugins;
+  }
+  // 0x100
+  else if (id && !plugin && !callback) {
+    return plugins[id];
+  }
+  // 0x110
+  else if (id && plugin && !callback) {
+    return plugins[id][plugin];
+  }
+  // 0x111
+  else if (id && plugin && callback) {
+    minplayer.bind.call(this, 'ready', id, plugin, callback);
+  }
+  // 0x011
+  else if (!id && plugin && callback) {
+    for (var id in plugins) {
+      minplayer.bind.call(this, 'ready', id, plugin, callback);
+    }
+  }
+  // 0x101
+  else if (id && !plugin && callback) {
+    for (var plugin in plugins[id]) {
+      minplayer.bind.call(this, 'ready', id, plugin, callback);
+    }
+  }
+  // 0x010
+  else if (!id && plugin && !callback) {
+    var plugin_types = {};
+    for (var id in plugins) {
+      if (plugins.hasOwnProperty(id) && plugins[id].hasOwnProperty(plugin)) {
+        plugin_types[id] = plugins[id][plugin];
+      }
+    }
+    return plugin_types;
+  }
+  // 0x001
+  else {
+    for (var id in plugins) {
+      for (var plugin in plugins[id]) {
+        minplayer.bind.call(this, 'ready', id, plugin, callback);
+      }
+    }
+  }
+};
+/** The minplayer namespace. */
+minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @extends minplayer.plugin
+ * @class Base class used to provide the display and options for any component
+ * deriving from this class.  Components who derive are expected to provide
+ * the elements that they define by implementing the getElements method.
+ *
+ * @param {string} name The name of this plugin.
+ * @param {object} context The jQuery context this component resides.
+ * @param {object} options The options for this component.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.display = function(name, context, options, queue) {
+
+  // See if we allow resize on this display.
+  this.allowResize = false;
+
+  if (context) {
+
+    // Set the display.
+    this.display = this.getDisplay(context, options);
+  }
+
+  // Derive from plugin
+  minplayer.plugin.call(this, name, context, options, queue);
+};
+
+/** Derive from minplayer.plugin. */
+minplayer.display.prototype = new minplayer.plugin();
+
+/** Reset the constructor. */
+minplayer.display.prototype.constructor = minplayer.display;
+
+/**
+ * Returns the display for this component.
+ *
+ * @param {object} context The original context.
+ * @param {object} options The options for this component.
+ * @return {object} The jQuery context for this display.
+ */
+minplayer.display.prototype.getDisplay = function(context, options) {
+  return jQuery(context);
+};
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.display.prototype.construct = function() {
+
+  // Call the plugin constructor.
+  minplayer.plugin.prototype.construct.call(this);
+
+  // Get the display elements.
+  this.elements = this.getElements();
+
+  // Only do this if they allow resize for this display.
+  if (this.allowResize) {
+
+    // Set the resize timeout and this pointer.
+    var resizeTimeout = 0;
+
+    // Add a handler to trigger a resize event.
+    jQuery(window).resize((function(display) {
+      return function() {
+        clearTimeout(resizeTimeout);
+        resizeTimeout = setTimeout(function() {
+          display.onResize();
+        }, 200);
+      };
+    })(this));
+  }
+};
+
+/**
+ * Called when the window resizes.
+ */
+minplayer.display.prototype.onResize = function() {
+};
+
+/**
+ * Gets the full screen element.
+ *
+ * @return {object} The display to be used for full screen support.
+ */
+minplayer.display.prototype.fullScreenElement = function() {
+  return this.display;
+};
+
+/**
+ * Called if you would like for your display item to show then hide.
+ *
+ * @param {object} element The element you would like to hide or show.
+ * @param {number} timeout The timeout to hide and show.
+ */
+minplayer.showThenHide = function(element, timeout) {
+
+  // Ensure we have a timeout.
+  timeout = timeout || 5000;
+
+  // If this has not yet been configured.
+  if (!element.showTimer) {
+
+    // Bind when they move the mouse.
+    jQuery(document).bind('mousemove', function() {
+      minplayer.showThenHide(element, timeout);
+    });
+  }
+
+  // Clear the timeout, and then setup the show then hide functionality.
+  clearTimeout(element.showTimer);
+
+  // Show the display.
+  element.show();
+
+  // Set a timer to hide it after the timeout.
+  element.showTimer = setTimeout(function() {
+    element.hide('slow');
+  }, timeout);
+};
+
+/**
+ * Make this display element go fullscreen.
+ *
+ * @param {boolean} full Tell the player to go into fullscreen or not.
+ */
+minplayer.display.prototype.fullscreen = function(full) {
+  var isFull = this.isFullScreen();
+  var element = this.fullScreenElement();
+  if (isFull && !full) {
+    element.removeClass('fullscreen');
+    if (screenfull) {
+      screenfull.exit();
+    }
+    this.trigger('fullscreen', false);
+  }
+  else if (!isFull && full) {
+    element.addClass('fullscreen');
+    if (screenfull) {
+      screenfull.request(element[0]);
+      screenfull.onchange = (function(display) {
+        return function(e) {
+          if (!screenfull.isFullscreen) {
+            display.fullscreen(false);
+          }
+        };
+      })(this);
+    }
+    this.trigger('fullscreen', true);
+  }
+};
+
+/**
+ * Toggle fullscreen.
+ */
+minplayer.display.prototype.toggleFullScreen = function() {
+  this.fullscreen(!this.isFullScreen());
+};
+
+/**
+ * Checks to see if we are in fullscreen mode.
+ *
+ * @return {boolean} TRUE - fullscreen, FALSE - otherwise.
+ */
+minplayer.display.prototype.isFullScreen = function() {
+  return this.fullScreenElement().hasClass('fullscreen');
+};
+
+/**
+ * Returns a scaled rectangle provided a ratio and the container rect.
+ *
+ * @param {number} ratio The width/height ratio of what is being scaled.
+ * @param {object} rect The bounding rectangle for scaling.
+ * @return {object} The Rectangle object of the scaled rectangle.
+ */
+minplayer.display.prototype.getScaledRect = function(ratio, rect) {
+  var scaledRect = {};
+  scaledRect.x = rect.x ? rect.x : 0;
+  scaledRect.y = rect.y ? rect.y : 0;
+  scaledRect.width = rect.width ? rect.width : 0;
+  scaledRect.height = rect.height ? rect.height : 0;
+  if (ratio) {
+    if ((rect.width / rect.height) > ratio) {
+      scaledRect.height = rect.height;
+      scaledRect.width = Math.floor(rect.height * ratio);
+    }
+    else {
+      scaledRect.height = Math.floor(rect.width / ratio);
+      scaledRect.width = rect.width;
+    }
+    scaledRect.x = Math.floor((rect.width - scaledRect.width) / 2);
+    scaledRect.y = Math.floor((rect.height - scaledRect.height) / 2);
+  }
+  return scaledRect;
+};
+
+/**
+ * Returns all the jQuery elements that this component uses.
+ *
+ * @return {object} An object which defines all the jQuery elements that
+ * this component uses.
+ */
+minplayer.display.prototype.getElements = function() {
+  return {};
+};
+
+/**
+ * Returns if this component is valid and exists within the DOM.
+ *
+ * @return {boolean} TRUE if the plugin display is valid.
+ */
+minplayer.display.prototype.isValid = function() {
+  return (this.display.length > 0);
+};
+
+/**
+ * From https://github.com/sindresorhus/screenfull.js
+ */
+/*global Element:true*/
+(function(window, document) {
+  'use strict';
+  var methods = (function() {
+    var methodMap = [
+      [
+        'requestFullscreen',
+        'exitFullscreen',
+        'fullscreenchange',
+        'fullscreen',
+        'fullscreenElement'
+      ],
+      [
+        'webkitRequestFullScreen',
+        'webkitCancelFullScreen',
+        'webkitfullscreenchange',
+        'webkitIsFullScreen',
+        'webkitCurrentFullScreenElement'
+      ],
+      [
+        'mozRequestFullScreen',
+        'mozCancelFullScreen',
+        'mozfullscreenchange',
+        'mozFullScreen',
+        'mozFullScreenElement'
+      ]
+    ];
+    for (var i = 0, l = methodMap.length; i < l; i++) {
+      var val = methodMap[i];
+      if (val[1] in document) {
+        return val;
+      }
+    }
+  })();
+
+  if (!methods) {
+    return window.screenfull = false;
+  }
+
+  var keyboardAllowed = 'ALLOW_KEYBOARD_INPUT' in Element;
+
+  var screenfull = {
+    init: function() {
+      document.addEventListener(methods[2], function(e) {
+        screenfull.isFullscreen = document[methods[3]];
+        screenfull.element = document[methods[4]];
+        screenfull.onchange(e);
+      });
+      return this;
+    },
+    isFullscreen: document[methods[3]],
+    element: document[methods[4]],
+    request: function(elem) {
+      elem = elem || document.documentElement;
+      elem[methods[0]](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
+      // Work around Safari 5.1 bug: reports support for keyboard in fullscreen
+      // even though it doesn't.
+      if (!document.isFullscreen) {
+        elem[methods[0]]();
+      }
+    },
+    exit: function() {
+      document[methods[1]]();
+    },
+    toggle: function(elem) {
+      if (this.isFullscreen) {
+        this.exit();
+      } else {
+        this.request(elem);
+      }
+    },
+    onchange: function() {}
+  };
+
+  window.screenfull = screenfull.init();
+})(window, document);
+// Add a way to instanciate using jQuery prototype.
+if (!jQuery.fn.minplayer) {
+
+  /**
+   * @constructor
+   *
+   * Define a jQuery minplayer prototype.
+   *
+   * @param {object} options The options for this jQuery prototype.
+   * @return {Array} jQuery object.
+   */
+  jQuery.fn.minplayer = function(options) {
+    return jQuery(this).each(function() {
+      options = options || {};
+      options.id = options.id || $(this).attr('id') || Math.random();
+      if (!minplayer.plugins[options.id]) {
+        options.template = options.template || 'default';
+        if (minplayer[options.template]) {
+          new minplayer[options.template](jQuery(this), options);
+        }
+        else {
+          new minplayer(jQuery(this), options);
+        }
+      }
+    });
+  };
+}
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The core media player class which governs the media player
+ * functionality.
+ *
+ * <p><strong>Usage:</strong>
+ * <pre><code>
+ *
+ *   // Create a media player.
+ *   var player = jQuery("#player").minplayer({
+ *
+ *   });
+ *
+ * </code></pre>
+ * </p>
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer = jQuery.extend(function(context, options) {
+
+  // Derive from display
+  minplayer.display.call(this, 'player', context, options);
+}, minplayer);
+
+/** Derive from minplayer.display. */
+minplayer.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.prototype.constructor = minplayer;
+
+/**
+ * Define a way to debug.
+ */
+minplayer.console = console || {log: function(data) {}};
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.prototype.construct = function() {
+
+  // Allow them to provide arguments based off of the DOM attributes.
+  jQuery.each(this.context[0].attributes, (function(player) {
+    return function(index, attr) {
+      player.options[attr.name] = player.options[attr.name] || attr.value;
+    };
+  })(this));
+
+  // Make sure we provide default options...
+  this.options = jQuery.extend({
+    id: 'player',
+    build: false,
+    wmode: 'transparent',
+    preload: true,
+    autoplay: false,
+    loop: false,
+    width: '100%',
+    height: '350px',
+    debug: false,
+    volume: 80,
+    files: [],
+    file: '',
+    preview: '',
+    attributes: {}
+  }, this.options);
+
+  // Call the minplayer display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  /** The controller for this player. */
+  this.controller = this.create('controller');
+
+  /** The play loader for this player. */
+  this.playLoader = this.create('playLoader');
+
+  /** Variable to store the current media player. */
+  this.currentPlayer = 'html5';
+
+  // Add key events to the window.
+  this.addKeyEvents();
+
+  // Now load these files.
+  this.load(this.getFiles());
+
+  // Add the player events.
+  this.addEvents();
+
+  // The player is ready.
+  this.ready();
+};
+
+/**
+ * We need to bind to events we are interested in.
+ */
+minplayer.prototype.addEvents = function() {
+  minplayer.get.call(this, this.options.id, null, (function(player) {
+    return function(plugin) {
+
+      // Bind to the error event.
+      plugin.bind('error', function(event, data) {
+
+        // If an error occurs within the html5 media player, then try
+        // to fall back to the flash player.
+        if (player.currentPlayer == 'html5') {
+          player.options.file.player = 'minplayer';
+          player.loadPlayer();
+        }
+        else {
+          player.error(data);
+        }
+      });
+
+      // Bind to the fullscreen event.
+      plugin.bind('fullscreen', function(event, data) {
+        player.resize();
+      });
+    };
+  })(this));
+};
+
+/**
+ * Sets an error on the player.
+ *
+ * @param {string} error The error to display on the player.
+ */
+minplayer.prototype.error = function(error) {
+  error = error || '';
+  if (this.elements.error) {
+
+    // Set the error text.
+    this.elements.error.text(error);
+    if (error) {
+      this.elements.error.show();
+    }
+    else {
+      this.elements.error.hide();
+    }
+  }
+};
+
+/**
+ * Adds key events to the player.
+ */
+minplayer.prototype.addKeyEvents = function() {
+  jQuery(document).bind('keydown', (function(player) {
+    return function(event) {
+      switch (event.keyCode) {
+        case 113: // ESC
+        case 27:  // Q
+          if (player.isFullScreen()) {
+            player.fullscreen(false);
+          }
+          break;
+      }
+    };
+  })(this));
+};
+
+/**
+ * Returns all the media files available for this player.
+ *
+ * @return {array} All the media files for this player.
+ */
+minplayer.prototype.getFiles = function() {
+  var files = [];
+  var mediaSrc = null;
+
+  // Get the files involved...
+  if (this.elements.media) {
+    mediaSrc = this.elements.media.attr('src');
+    if (mediaSrc) {
+      files.push({'path': mediaSrc});
+    }
+    jQuery('source', this.elements.media).each(function() {
+      files.push({
+        'path': jQuery(this).attr('src'),
+        'mimetype': jQuery(this).attr('type'),
+        'codecs': jQuery(this).attr('codecs')
+      });
+    });
+  }
+
+  return files;
+};
+
+/**
+ * Returns the full media player object.
+ * @param {array} files An array of files to chose from.
+ * @return {object} The best media file to play in the current browser.
+ */
+minplayer.prototype.getMediaFile = function(files) {
+
+  // If there are no files then return null.
+  if (!files) {
+    return null;
+  }
+
+  // If the file is a single string, then return the file object.
+  if (typeof files === 'string') {
+    return new minplayer.file({'path': files});
+  }
+
+  // If the file is already a file object then just return.
+  if (files.path || files.id) {
+    return new minplayer.file(files);
+  }
+
+  // Add the files and get the best player to play.
+  var i = files.length, bestPriority = 0, mFile = null, file = null;
+  while (i--) {
+    file = files[i];
+
+    // Get the minplayer file object.
+    if (typeof file === 'string') {
+      file = new minplayer.file({'path': file});
+    }
+    else {
+      file = new minplayer.file(file);
+    }
+
+    // Determine the best file for this browser.
+    if (file.priority > bestPriority) {
+      mFile = file;
+    }
+  }
+
+  // Return the best minplayer file.
+  return mFile;
+};
+
+/**
+ * Loads a media player based on the current file.
+ */
+minplayer.prototype.loadPlayer = function() {
+
+  // Do nothing if there isn't a file.
+  if (!this.options.file) {
+    this.error('No media found.');
+    return;
+  }
+
+  if (!this.options.file.player) {
+    this.error('Cannot play media: ' + this.options.file.mimetype);
+    return;
+  }
+
+  // Reset the error.
+  this.error();
+
+  // Only destroy if the current player is different than the new player.
+  var player = this.options.file.player.toString();
+
+  // If there isn't media or if the players are different.
+  if (!this.media || (player !== this.currentPlayer)) {
+
+    // Set the current media player.
+    this.currentPlayer = player;
+
+    // Do nothing if we don't have a display.
+    if (!this.elements.display) {
+      this.error('No media display found.');
+      return;
+    }
+
+    // Destroy the current media.
+    var queue = {};
+    if (this.media) {
+      queue = this.media.queue;
+      this.media.destroy();
+    }
+
+    // Get the class name and create the new player.
+    pClass = minplayer.players[this.options.file.player];
+
+    // Create the new media player.
+    this.options.mediaelement = this.elements.media;
+    this.media = new pClass(this.elements.display, this.options, queue);
+
+    // Now get the media when it is ready.
+    this.get('media', (function(player) {
+      return function(media) {
+
+        // Load the media.
+        media.load(player.options.file);
+      };
+    })(this));
+  }
+  // If the media object already exists...
+  else if (this.media) {
+
+    // Now load the different media file.
+    this.media.load(this.options.file);
+  }
+};
+
+/**
+ * Load a set of files or a single file for the media player.
+ *
+ * @param {array} files An array of files to chose from to load.
+ */
+minplayer.prototype.load = function(files) {
+
+  // Set the id and class.
+  var id = '', pClass = '';
+
+  // If no file was provided, then get it.
+  this.options.files = files || this.options.files;
+  this.options.file = this.getMediaFile(this.options.files);
+
+  // Now load the player.
+  this.loadPlayer();
+};
+
+/**
+ * Called when the player is resized.
+ */
+minplayer.prototype.resize = function() {
+
+  // Call onRezie for each plugin.
+  this.get(function(plugin) {
+    plugin.onResize();
+  });
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class A class to easily handle images.
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer.image = function(context, options) {
+
+  // Determine if the image is loaded.
+  this.loaded = false;
+
+  // The image loader.
+  this.loader = null;
+
+  // The ratio of the image.
+  this.ratio = 0;
+
+  // The image element.
+  this.img = null;
+
+  // Derive from display
+  minplayer.display.call(this, 'image', context, options);
+};
+
+/** Derive from minplayer.display. */
+minplayer.image.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.image.prototype.constructor = minplayer.image;
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.image.prototype.construct = function() {
+
+  // Say we need to resize.
+  this.allowResize = true;
+
+  // Call the media display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Set the container to not show any overflow...
+  this.display.css('overflow', 'hidden');
+
+  /** The loader for the image. */
+  this.loader = new Image();
+
+  /** Register for when the image is loaded within the loader. */
+  this.loader.onload = (function(image) {
+    return function() {
+      image.loaded = true;
+      image.ratio = (image.loader.width / image.loader.height);
+      image.resize();
+      image.trigger('loaded');
+    };
+  })(this);
+
+  // We are now ready.
+  this.ready();
+};
+
+/**
+ * Loads an image.
+ *
+ * @param {string} src The source of the image to load.
+ */
+minplayer.image.prototype.load = function(src) {
+
+  // First clear the previous image.
+  this.clear(function() {
+
+    // Create the new image, and append to the display.
+    this.display.empty();
+    this.img = jQuery(document.createElement('img')).attr({src: ''}).hide();
+    this.display.append(this.img);
+    this.loader.src = src;
+  });
+};
+
+/**
+ * Clears an image.
+ *
+ * @param {function} callback Called when the image is done clearing.
+ */
+minplayer.image.prototype.clear = function(callback) {
+  this.loaded = false;
+  if (this.img) {
+    this.img.fadeOut((function(image) {
+      return function() {
+        image.img.attr('src', '');
+        image.loader.src = '';
+        $(this).remove();
+        callback.call(image);
+      };
+    })(this));
+  }
+  else {
+    callback.call(this);
+  }
+};
+
+/**
+ * Resize the image provided a width and height or nothing.
+ *
+ * @param {integer} width (optional) The width of the container.
+ * @param {integer} height (optional) The height of the container.
+ */
+minplayer.image.prototype.resize = function(width, height) {
+  width = width || this.display.width();
+  height = height || this.display.height();
+  if (width && height && this.loaded) {
+
+    // Get the scaled rectangle.
+    var rect = this.getScaledRect(this.ratio, {
+      width: width,
+      height: height
+    });
+
+    // Now set this image to the new size.
+    if (this.img) {
+      this.img.attr('src', this.loader.src).css({
+        marginLeft: rect.x,
+        marginTop: rect.y,
+        width: rect.width,
+        height: rect.height
+      });
+    }
+
+    // Show the container.
+    this.img.fadeIn();
+  }
+};
+
+/**
+ * @see minplayer.display#onResize
+ */
+minplayer.image.prototype.onResize = function() {
+
+  // Resize the image to fit.
+  this.resize();
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class A wrapper class used to provide all the data necessary to control an
+ * individual file within this media player.
+ *
+ * @param {object} file A media file object with minimal required information.
+ */
+minplayer.file = function(file) {
+  this.duration = file.duration || 0;
+  this.bytesTotal = file.bytesTotal || 0;
+  this.quality = file.quality || 0;
+  this.stream = file.stream || '';
+  this.path = file.path || '';
+  this.codecs = file.codecs || '';
+
+  // These should be provided, but just in case...
+  this.extension = file.extension || this.getFileExtension();
+  this.mimetype = file.mimetype || file.filemime || this.getMimeType();
+  this.type = file.type || this.getType();
+
+  // Fail safe to try and guess the mimetype and media type.
+  if (!this.type) {
+    this.mimetype = this.getMimeType();
+    this.type = this.getType();
+  }
+
+  // Get the player.
+  this.player = file.player || this.getBestPlayer();
+  this.priority = file.priority || this.getPriority();
+  this.id = file.id || this.getId();
+};
+
+/**
+ * Returns the best player for the job.
+ *
+ * @return {string} The best player to play the media file.
+ */
+minplayer.file.prototype.getBestPlayer = function() {
+  var bestplayer = null, bestpriority = 0;
+  jQuery.each(minplayer.players, (function(file) {
+    return function(name, player) {
+      var priority = player.getPriority();
+      if (player.canPlay(file) && (priority > bestpriority)) {
+        bestplayer = name;
+        bestpriority = priority;
+      }
+    };
+  })(this));
+  return bestplayer;
+};
+
+/**
+ * The priority of this file is determined by the priority of the best
+ * player multiplied by the priority of the mimetype.
+ *
+ * @return {integer} The priority of the media file.
+ */
+minplayer.file.prototype.getPriority = function() {
+  var priority = 1;
+  if (this.player) {
+    priority = minplayer.players[this.player].getPriority();
+  }
+  switch (this.mimetype) {
+    case 'video/x-webm':
+    case 'video/webm':
+    case 'application/octet-stream':
+      return priority * 10;
+    case 'video/mp4':
+    case 'audio/mp4':
+    case 'audio/mpeg':
+      return priority * 9;
+    case 'video/ogg':
+    case 'audio/ogg':
+    case 'video/quicktime':
+      return priority * 8;
+    default:
+      return priority * 5;
+  }
+};
+
+/**
+ * Returns the file extension of the file path.
+ *
+ * @return {string} The file extension.
+ */
+minplayer.file.prototype.getFileExtension = function() {
+  return this.path.substring(this.path.lastIndexOf('.') + 1).toLowerCase();
+};
+
+/**
+ * Returns the proper mimetype based off of the extension.
+ *
+ * @return {string} The mimetype of the file based off of extension.
+ */
+minplayer.file.prototype.getMimeType = function() {
+  switch (this.extension) {
+    case 'mp4': case 'm4v': case 'flv': case 'f4v':
+      return 'video/mp4';
+    case'webm':
+      return 'video/webm';
+    case 'ogg': case 'ogv':
+      return 'video/ogg';
+    case '3g2':
+      return 'video/3gpp2';
+    case '3gpp':
+    case '3gp':
+      return 'video/3gpp';
+    case 'mov':
+      return 'video/quicktime';
+    case'swf':
+      return 'application/x-shockwave-flash';
+    case 'oga':
+      return 'audio/ogg';
+    case 'mp3':
+      return 'audio/mpeg';
+    case 'm4a': case 'f4a':
+      return 'audio/mp4';
+    case 'aac':
+      return 'audio/aac';
+    case 'wav':
+      return 'audio/vnd.wave';
+    case 'wma':
+      return 'audio/x-ms-wma';
+    default:
+      return 'unknown';
+  }
+};
+
+/**
+ * The type of media this is: video or audio.
+ *
+ * @return {string} "video" or "audio" based on what the type of media this
+ * is.
+ */
+minplayer.file.prototype.getType = function() {
+  switch (this.mimetype) {
+    case 'video/mp4':
+    case 'video/webm':
+    case 'application/octet-stream':
+    case 'video/x-webm':
+    case 'video/ogg':
+    case 'video/3gpp2':
+    case 'video/3gpp':
+    case 'video/quicktime':
+      return 'video';
+    case 'audio/mp3':
+    case 'audio/mp4':
+    case 'audio/ogg':
+    case 'audio/mpeg':
+      return 'audio';
+    default:
+      return '';
+  }
+};
+
+/**
+ * Returns the ID for this media file.
+ *
+ * @return {string} The id for this media file which is provided by the player.
+ */
+minplayer.file.prototype.getId = function() {
+  var player = minplayer.players[this.player];
+  return (player && player.getMediaId) ? player.getMediaId(this) : '';
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The play loader base class, which is used to control the busy
+ * cursor, big play button, and the opaque background which shows when the
+ * player is paused.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer.playLoader = function(context, options) {
+
+  // Define the flags that control the busy cursor.
+  this.busy = new minplayer.flags();
+
+  // Define the flags that control the big play button.
+  this.bigPlay = new minplayer.flags();
+
+  /** The preview image. */
+  this.preview = null;
+
+  // Derive from display
+  minplayer.display.call(this, 'playLoader', context, options);
+};
+
+/** Derive from minplayer.display. */
+minplayer.playLoader.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.playLoader.prototype.constructor = minplayer.playLoader;
+
+/**
+ * The constructor.
+ */
+minplayer.playLoader.prototype.construct = function() {
+
+  // Call the media display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Get the media plugin.
+  this.get('media', function(media) {
+
+    // Only bind if this player does not have its own play loader.
+    if (!media.hasPlayLoader()) {
+
+      // Get the poster image.
+      if (!this.options.preview) {
+        this.options.preview = media.elements.media.attr('poster');
+      }
+
+      // Reset the media's poster image.
+      media.elements.media.attr('poster', '');
+
+      // Load the preview image.
+      this.loadPreview();
+
+      // Trigger a play event when someone clicks on the controller.
+      if (this.elements.bigPlay) {
+        this.elements.bigPlay.unbind().bind('click', function(event) {
+          event.preventDefault();
+          jQuery(this).hide();
+          media.play();
+        });
+      }
+
+      // Bind to the player events to control the play loader.
+      media.unbind('loadstart').bind('loadstart', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', true);
+          playLoader.bigPlay.setFlag('media', true);
+          if (playLoader.preview) {
+            playLoader.elements.preview.show();
+          }
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('waiting', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', true);
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('loadeddata', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', false);
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('playing', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', false);
+          playLoader.bigPlay.setFlag('media', false);
+          if (playLoader.preview) {
+            playLoader.elements.preview.hide();
+          }
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('pause', (function(playLoader) {
+        return function(event) {
+          playLoader.bigPlay.setFlag('media', true);
+          playLoader.checkVisibility();
+        };
+      })(this));
+    }
+    else {
+
+      // Hide the busy cursor.
+      if (this.elements.busy) {
+        this.elements.busy.unbind().hide();
+      }
+
+      // Hide the big play button.
+      if (this.elements.bigPlay) {
+        this.elements.bigPlay.unbind().hide();
+      }
+
+      // Hide the display.
+      this.display.unbind().hide();
+    }
+  });
+
+  // We are now ready.
+  this.ready();
+};
+
+/**
+ * Loads the preview image.
+ */
+minplayer.playLoader.prototype.loadPreview = function() {
+
+  // If the preview element exists.
+  if (this.elements.preview) {
+
+    // If there is a preview to show...
+    if (this.options.preview) {
+
+      // Say that this has a preview.
+      this.elements.preview.addClass('has-preview').show();
+
+      // Create a new preview image.
+      this.preview = new minplayer.image(this.elements.preview, this.options);
+
+      // Create the image.
+      this.preview.load(this.options.preview);
+    }
+    else {
+
+      // Hide the preview.
+      this.elements.preview.hide();
+    }
+  }
+};
+
+/**
+ * Hide or show certain elements based on the state of the busy and big play
+ * button.
+ */
+minplayer.playLoader.prototype.checkVisibility = function() {
+
+  // Hide or show the busy cursor based on the flags.
+  if (this.busy.flag) {
+    this.elements.busy.show();
+  }
+  else {
+    this.elements.busy.hide();
+  }
+
+  // Hide or show the big play button based on the flags.
+  if (this.bigPlay.flag) {
+    this.elements.bigPlay.show();
+  }
+  else {
+    this.elements.bigPlay.hide();
+  }
+
+  // Show the control either flag is set.
+  if (this.bigPlay.flag || this.busy.flag) {
+    this.display.show();
+  }
+
+  // Hide the whole control if both flags are 0.
+  if (!this.bigPlay.flag && !this.busy.flag) {
+    this.display.hide();
+  }
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The base media player class where all media players derive from.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.base = function(context, options, queue) {
+
+  // Derive from display
+  minplayer.display.call(this, 'media', context, options, queue);
+};
+
+/** Derive from minplayer.display. */
+minplayer.players.base.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.players.base.prototype.constructor = minplayer.players.base;
+
+/**
+ * @see minplayer.display.getElements
+ * @this minplayer.players.base
+ * @return {object} The elements for this display.
+ */
+minplayer.players.base.prototype.getElements = function() {
+  var elements = minplayer.display.prototype.getElements.call(this);
+  return jQuery.extend(elements, {
+    media: this.options.mediaelement
+  });
+};
+
+/**
+ * Get the priority of this media player.
+ *
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.base.getPriority = function() {
+  return 0;
+};
+
+/**
+ * Returns the ID for the media being played.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {string} The ID for the provided media.
+ */
+minplayer.players.base.getMediaId = function(file) {
+  return '';
+};
+
+/**
+ * Determine if we can play the media file.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.base.canPlay = function(file) {
+  return false;
+};
+
+/**
+ * @see minplayer.plugin.construct
+ * @this minplayer.players.base
+ */
+minplayer.players.base.prototype.construct = function() {
+
+  // Call the media display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Clear the media player.
+  this.clear();
+
+  /** The currently loaded media file. */
+  this.mediaFile = this.options.file;
+
+  // Get the player display object.
+  if (!this.playerFound()) {
+
+    // Remove the media element if found
+    if (this.elements.media) {
+      this.elements.media.remove();
+    }
+
+    // Create a new media player element.
+    this.elements.media = jQuery(this.create());
+    this.display.html(this.elements.media);
+  }
+
+  // Get the player object...
+  this.player = this.getPlayer();
+
+  // Set the focus of the element based on if they click in or outside of it.
+  jQuery(document).bind('click', (function(player) {
+    return function(event) {
+      if (jQuery(event.target).closest('#' + player.options.id).length == 0) {
+        player.hasFocus = false;
+      }
+      else {
+        player.hasFocus = true;
+      }
+    };
+  })(this));
+
+  // Bind to key events...
+  jQuery(document).bind('keydown', (function(player) {
+    return function(event) {
+      if (player.hasFocus) {
+        event.preventDefault();
+        switch (event.keyCode) {
+          case 32:  // SPACE
+          case 179: // GOOGLE play/pause button.
+            if (player.playing) {
+              player.pause();
+            }
+            else {
+              player.play();
+            }
+            break;
+          case 38:  // UP
+            player.setVolumeRelative(0.1);
+            break;
+          case 40:  // DOWN
+            player.setVolumeRelative(-0.1);
+            break;
+          case 37:  // LEFT
+          case 227: // GOOGLE TV REW
+            player.seekRelative(-0.05);
+            break;
+          case 39:  // RIGHT
+          case 228: // GOOGLE TV FW
+            player.seekRelative(0.05);
+            break;
+        }
+      }
+    };
+  })(this));
+};
+
+/**
+ * @see minplayer.plugin.destroy.
+ */
+minplayer.players.base.prototype.destroy = function() {
+  minplayer.plugin.prototype.destroy.call(this);
+  this.clear();
+};
+
+/**
+ * Clears the media player.
+ */
+minplayer.players.base.prototype.clear = function() {
+
+  // Reset the ready flag.
+  this.playerReady = false;
+
+  // Reset the player.
+  this.reset();
+
+  // If the player exists, then unbind all events.
+  if (this.player) {
+    jQuery(this.player).unbind();
+  }
+};
+
+/**
+ * Resets all variables.
+ */
+minplayer.players.base.prototype.reset = function() {
+
+  // The duration of the player.
+  this.duration = new minplayer.async();
+
+  // The current play time of the player.
+  this.currentTime = new minplayer.async();
+
+  // The amount of bytes loaded in the player.
+  this.bytesLoaded = new minplayer.async();
+
+  // The total amount of bytes for the media.
+  this.bytesTotal = new minplayer.async();
+
+  // The bytes that the download started with.
+  this.bytesStart = new minplayer.async();
+
+  // The current volume of the player.
+  this.volume = new minplayer.async();
+
+  // Reset focus.
+  this.hasFocus = false;
+
+  // We are not playing.
+  this.playing = false;
+
+  // We are not loading.
+  this.loading = false;
+
+  // Tell everyone else we reset.
+  this.trigger('pause');
+  this.trigger('waiting');
+  this.trigger('progress', {loaded: 0, total: 0, start: 0});
+  this.trigger('timeupdate', {currentTime: 0, duration: 0});
+};
+
+/**
+ * Called when the player is ready to recieve events and commands.
+ */
+minplayer.players.base.prototype.onReady = function() {
+
+  // Only continue if we are not already ready.
+  if (this.playerReady) {
+    return;
+  }
+
+  // Set the ready flag.
+  this.playerReady = true;
+
+  // Set the volume to the default.
+  this.setVolume(this.options.volume / 100);
+
+  // Setup the progress interval.
+  this.loading = true;
+
+  // Create a poll to get the progress.
+  this.poll((function(player) {
+    return function() {
+
+      // Only do this if the play interval is set.
+      if (player.loading) {
+
+        // Get the bytes loaded asynchronously.
+        player.getBytesLoaded(function(bytesLoaded) {
+
+          // Get the bytes total asynchronously.
+          player.getBytesTotal(function(bytesTotal) {
+
+            // Trigger an event about the progress.
+            if (bytesLoaded || bytesTotal) {
+
+              // Get the bytes start, but don't require it.
+              var bytesStart = 0;
+              player.getBytesStart(function(val) {
+                bytesStart = val;
+              });
+
+              // Trigger a progress event.
+              player.trigger('progress', {
+                loaded: bytesLoaded,
+                total: bytesTotal,
+                start: bytesStart
+              });
+
+              // Say we are not longer loading if they are equal.
+              if (bytesLoaded >= bytesTotal) {
+                player.loading = false;
+              }
+            }
+          });
+        });
+      }
+
+      // Keep polling as long as its loading...
+      return player.loading;
+    };
+  })(this), 1000);
+
+  // We are now ready.
+  this.ready();
+
+  // Trigger that the load has started.
+  this.trigger('loadstart');
+};
+
+/**
+ * Should be called when the media is playing.
+ */
+minplayer.players.base.prototype.onPlaying = function() {
+
+  // Trigger an event that we are playing.
+  this.trigger('playing');
+
+  // Say that this player has focus.
+  this.hasFocus = true;
+
+  // Set the playInterval to true.
+  this.playing = true;
+
+  // Create a poll to get the timeupate.
+  this.poll((function(player) {
+    return function() {
+
+      // Only do this if the play interval is set.
+      if (player.playing) {
+
+        // Get the current time asyncrhonously.
+        player.getCurrentTime(function(currentTime) {
+
+          // Get the duration asynchronously.
+          player.getDuration(function(duration) {
+
+            // Convert these to floats.
+            currentTime = parseFloat(currentTime);
+            duration = parseFloat(duration);
+
+            // Trigger an event about the progress.
+            if (currentTime || duration) {
+
+              // Trigger an update event.
+              player.trigger('timeupdate', {
+                currentTime: currentTime,
+                duration: duration
+              });
+            }
+          });
+        });
+      }
+
+      // Keep polling as long as it is playing.
+      return player.playing;
+    };
+  })(this), 1000);
+};
+
+/**
+ * Should be called when the media is paused.
+ */
+minplayer.players.base.prototype.onPaused = function() {
+
+  // Trigger an event that we are paused.
+  this.trigger('pause');
+
+  // Remove focus.
+  this.hasFocus = false;
+
+  // Say we are not playing.
+  this.playing = false;
+};
+
+/**
+ * Should be called when the media is complete.
+ */
+minplayer.players.base.prototype.onComplete = function() {
+  // Stop the intervals.
+  this.playing = false;
+  this.loading = false;
+  this.hasFocus = false;
+  this.trigger('ended');
+};
+
+/**
+ * Should be called when the media is done loading.
+ */
+minplayer.players.base.prototype.onLoaded = function() {
+  this.trigger('loadeddata');
+};
+
+/**
+ * Should be called when the player is waiting.
+ */
+minplayer.players.base.prototype.onWaiting = function() {
+  this.trigger('waiting');
+};
+
+/**
+ * Called when an error occurs.
+ *
+ * @param {string} errorCode The error that was triggered.
+ */
+minplayer.players.base.prototype.onError = function(errorCode) {
+  this.hasFocus = false;
+  this.trigger('error', errorCode);
+};
+
+/**
+ * @see minplayer.players.base#isReady
+ * @return {boolean} Checks to see if the Flash is ready.
+ */
+minplayer.players.base.prototype.isReady = function() {
+
+  // Return that the player is set and the ready flag is good.
+  return (this.player && this.playerReady);
+};
+
+/**
+ * Determines if the player should show the playloader.
+ *
+ * @return {bool} If this player implements its own playLoader.
+ */
+minplayer.players.base.prototype.hasPlayLoader = function() {
+  return false;
+};
+
+/**
+ * Returns if the media player is already within the DOM.
+ *
+ * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
+ */
+minplayer.players.base.prototype.playerFound = function() {
+  return false;
+};
+
+/**
+ * Creates the media player and inserts it in the DOM.
+ *
+ * @return {object} The media player entity.
+ */
+minplayer.players.base.prototype.create = function() {
+  this.reset();
+  return null;
+};
+
+/**
+ * Returns the media player object.
+ *
+ * @return {object} The media player object.
+ */
+minplayer.players.base.prototype.getPlayer = function() {
+  return this.player;
+};
+
+/**
+ * Loads a new media player.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ */
+minplayer.players.base.prototype.load = function(file) {
+
+  // Store the media file for future lookup.
+  var isString = (typeof this.mediaFile == 'string');
+  var path = isString ? this.mediaFile : this.mediaFile.path;
+  if (file && (file.path != path)) {
+    this.reset();
+    this.mediaFile = file;
+  }
+};
+
+/**
+ * Play the loaded media file.
+ */
+minplayer.players.base.prototype.play = function() {
+};
+
+/**
+ * Pause the loaded media file.
+ */
+minplayer.players.base.prototype.pause = function() {
+};
+
+/**
+ * Stop the loaded media file.
+ */
+minplayer.players.base.prototype.stop = function() {
+  this.playing = false;
+  this.loading = false;
+  this.hasFocus = false;
+};
+
+/**
+ * Seeks to relative position.
+ *
+ * @param {number} pos Relative position.  -1 to 1 (percent), > 1 (seconds).
+ */
+minplayer.players.base.prototype.seekRelative = function(pos) {
+
+  // Get the current time asyncrhonously.
+  this.getCurrentTime((function(player) {
+    return function(currentTime) {
+
+      // Get the duration asynchronously.
+      player.getDuration(function(duration) {
+
+        // Only do this if we have a duration.
+        if (duration) {
+
+          // Get the position.
+          var seekPos = 0;
+          if ((pos > -1) && (pos < 1)) {
+            seekPos = (currentTime / duration) + parseFloat(pos);
+          }
+          else {
+            seekPos = (currentTime + parseFloat(pos)) / duration;
+          }
+
+          // Set the seek value.
+          player.seek(seekPos);
+        }
+      });
+    };
+  })(this));
+};
+
+/**
+ * Seek the loaded media.
+ *
+ * @param {number} pos The position to seek the minplayer. 0 to 1.
+ */
+minplayer.players.base.prototype.seek = function(pos) {
+};
+
+/**
+ * Set the volume of the loaded minplayer.
+ *
+ * @param {number} vol -1 to 1 - The relative amount to increase or decrease.
+ */
+minplayer.players.base.prototype.setVolumeRelative = function(vol) {
+
+  // Get the volume
+  this.getVolume((function(player) {
+    return function(newVol) {
+      newVol += parseFloat(vol);
+      newVol = (newVol < 0) ? 0 : newVol;
+      newVol = (newVol > 1) ? 1 : newVol;
+      player.setVolume(newVol);
+    };
+  })(this));
+};
+
+/**
+ * Set the volume of the loaded minplayer.
+ *
+ * @param {number} vol The volume to set the media. 0 to 1.
+ */
+minplayer.players.base.prototype.setVolume = function(vol) {
+  this.trigger('volumeupdate', vol);
+};
+
+/**
+ * Get the volume from the loaded media.
+ *
+ * @param {function} callback Called when the volume is determined.
+ * @return {number} The volume of the media; 0 to 1.
+ */
+minplayer.players.base.prototype.getVolume = function(callback) {
+  return this.volume.get(callback);
+};
+
+/**
+ * Get the current time for the media being played.
+ *
+ * @param {function} callback Called when the time is determined.
+ * @return {number} The volume of the media; 0 to 1.
+ */
+minplayer.players.base.prototype.getCurrentTime = function(callback) {
+  return this.currentTime.get(callback);
+};
+
+/**
+ * Return the duration of the loaded media.
+ *
+ * @param {function} callback Called when the duration is determined.
+ * @return {number} The duration of the loaded media.
+ */
+minplayer.players.base.prototype.getDuration = function(callback) {
+  return this.duration.get(callback);
+};
+
+/**
+ * Return the start bytes for the loaded media.
+ *
+ * @param {function} callback Called when the start bytes is determined.
+ * @return {int} The bytes that were started.
+ */
+minplayer.players.base.prototype.getBytesStart = function(callback) {
+  return this.bytesStart.get(callback);
+};
+
+/**
+ * Return the bytes of media loaded.
+ *
+ * @param {function} callback Called when the bytes loaded is determined.
+ * @return {int} The amount of bytes loaded.
+ */
+minplayer.players.base.prototype.getBytesLoaded = function(callback) {
+  return this.bytesLoaded.get(callback);
+};
+
+/**
+ * Return the total amount of bytes.
+ *
+ * @param {function} callback Called when the bytes total is determined.
+ * @return {int} The total amount of bytes for this media.
+ */
+minplayer.players.base.prototype.getBytesTotal = function(callback) {
+  return this.bytesTotal.get(callback);
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The HTML5 media player implementation.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.html5 = function(context, options, queue) {
+
+  // Derive players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.html5.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.html5.prototype.constructor = minplayer.players.html5;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.html5.getPriority = function() {
+  return 10;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.html5.canPlay = function(file) {
+  switch (file.mimetype) {
+    case 'video/ogg':
+      return !!minplayer.playTypes.videoOGG;
+    case 'video/mp4':
+    case 'video/x-mp4':
+    case 'video/m4v':
+    case 'video/x-m4v':
+      return !!minplayer.playTypes.videoH264;
+    case 'video/x-webm':
+    case 'video/webm':
+    case 'application/octet-stream':
+      return !!minplayer.playTypes.videoWEBM;
+    case 'audio/ogg':
+      return !!minplayer.playTypes.audioOGG;
+    case 'audio/mpeg':
+      return !!minplayer.playTypes.audioMP3;
+    case 'audio/mp4':
+      return !!minplayer.playTypes.audioMP4;
+    default:
+      return false;
+  }
+};
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.players.html5.prototype.construct = function() {
+
+  // Call base constructor.
+  minplayer.players.base.prototype.construct.call(this);
+
+  // For the HTML5 player, we will just pass events along...
+  if (this.player) {
+
+    this.player.addEventListener('abort', (function(player) {
+      return function() {
+        player.trigger('abort');
+      };
+    })(this), false);
+    this.player.addEventListener('loadstart', (function(player) {
+      return function() {
+        player.onReady();
+      };
+    })(this), false);
+    this.player.addEventListener('loadeddata', (function(player) {
+      return function() {
+        player.onLoaded();
+      };
+    })(this), false);
+    this.player.addEventListener('loadedmetadata', (function(player) {
+      return function() {
+        player.onLoaded();
+      };
+    })(this), false);
+    this.player.addEventListener('canplaythrough', (function(player) {
+      return function() {
+        player.onLoaded();
+      };
+    })(this), false);
+    this.player.addEventListener('ended', (function(player) {
+      return function() {
+        player.onComplete();
+      };
+    })(this), false);
+    this.player.addEventListener('pause', (function(player) {
+      return function() {
+        player.onPaused();
+      };
+    })(this), false);
+    this.player.addEventListener('play', (function(player) {
+      return function() {
+        player.onPlaying();
+      };
+    })(this), false);
+    this.player.addEventListener('playing', (function(player) {
+      return function() {
+        player.onPlaying();
+      };
+    })(this), false);
+    this.player.addEventListener('error', (function(player) {
+      return function() {
+        player.trigger('error', 'An error occured - ' + this.error.code);
+      };
+    })(this), false);
+    this.player.addEventListener('waiting', (function(player) {
+      return function() {
+        player.onWaiting();
+      };
+    })(this), false);
+    this.player.addEventListener('durationchange', (function(player) {
+      return function() {
+        player.duration.set(this.duration);
+        player.trigger('durationchange', {duration: this.duration});
+      };
+    })(this), false);
+    this.player.addEventListener('progress', (function(player) {
+      return function(event) {
+        player.bytesTotal.set(event.total);
+        player.bytesLoaded.set(event.loaded);
+      };
+    })(this), false);
+
+    // Say we are ready.
+    this.onReady();
+  }
+};
+
+/**
+ * @see minplayer.players.base#playerFound
+ * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
+ */
+minplayer.players.html5.prototype.playerFound = function() {
+  return (this.display.find(this.mediaFile.type).length > 0);
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.html5.prototype.create = function() {
+  minplayer.players.base.prototype.create.call(this);
+  var element = jQuery(document.createElement(this.mediaFile.type))
+  .attr(this.options.attributes)
+  .append(
+    jQuery(document.createElement('source')).attr({
+      'src': this.mediaFile.path
+    })
+  );
+
+  // Fix the fluid width and height.
+  element.eq(0)[0].setAttribute('width', '100%');
+  element.eq(0)[0].setAttribute('height', '100%');
+  return element;
+};
+
+/**
+ * @see minplayer.players.base#getPlayer
+ * @return {object} The media player object.
+ */
+minplayer.players.html5.prototype.getPlayer = function() {
+  return this.elements.media.eq(0)[0];
+};
+
+/**
+ * @see minplayer.players.base#load
+ */
+minplayer.players.html5.prototype.load = function(file) {
+
+  if (file) {
+
+    // Get the current source.
+    var src = this.elements.media.attr('src');
+    if (!src) {
+      src = jQuery('source', this.elements.media).eq(0).attr('src');
+    }
+
+    // If the source is different.
+    if (src != file.path) {
+
+      // Change the source...
+      var code = '<source src="' + file.path + '">';
+      this.elements.media.removeAttr('src').empty().html(code);
+    }
+  }
+
+  // Always call the base first on load...
+  minplayer.players.base.prototype.load.call(this, file);
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.html5.prototype.play = function() {
+  minplayer.players.base.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.play();
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.html5.prototype.pause = function() {
+  minplayer.players.base.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.pause();
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.html5.prototype.stop = function() {
+  minplayer.players.base.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.pause();
+    this.player.src = '';
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.html5.prototype.seek = function(pos) {
+  minplayer.players.base.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.currentTime = pos;
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.html5.prototype.setVolume = function(vol) {
+  minplayer.players.base.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.player.volume = vol;
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.html5.prototype.getVolume = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.volume);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getDuration
+ */
+minplayer.players.html5.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.duration);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getCurrentTime
+ */
+minplayer.players.html5.prototype.getCurrentTime = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.currentTime);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesLoaded
+ */
+minplayer.players.html5.prototype.getBytesLoaded = function(callback) {
+  if (this.isReady()) {
+    var loaded = 0;
+
+    // Check several different possibilities.
+    if (this.bytesLoaded.value) {
+      loaded = this.bytesLoaded.value;
+    }
+    else if (this.player.buffered &&
+        this.player.buffered.length > 0 &&
+        this.player.buffered.end &&
+        this.player.duration) {
+      loaded = this.player.buffered.end(0);
+    }
+    else if (this.player.bytesTotal != undefined &&
+             this.player.bytesTotal > 0 &&
+             this.player.bufferedBytes != undefined) {
+      loaded = this.player.bufferedBytes;
+    }
+
+    // Return the loaded amount.
+    callback(loaded);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesTotal
+ */
+minplayer.players.html5.prototype.getBytesTotal = function(callback) {
+  if (this.isReady()) {
+
+    var total = 0;
+
+    // Check several different possibilities.
+    if (this.bytesTotal.value) {
+      total = this.bytesTotal.value;
+    }
+    else if (this.player.buffered &&
+        this.player.buffered.length > 0 &&
+        this.player.buffered.end &&
+        this.player.duration) {
+      total = this.player.duration;
+    }
+    else if (this.player.bytesTotal != undefined &&
+             this.player.bytesTotal > 0 &&
+             this.player.bufferedBytes != undefined) {
+      total = this.player.bytesTotal;
+    }
+
+    // Return the loaded amount.
+    callback(total);
+  }
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The Flash media player class to control the flash fallback.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.flash = function(context, options, queue) {
+
+  // Derive from players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.flash.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.flash.prototype.constructor = minplayer.players.flash;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.flash.getPriority = function() {
+  return 0;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.flash.canPlay = function(file) {
+  return false;
+};
+
+/**
+ * API to return the Flash player code provided params.
+ *
+ * @param {object} params The params used to populate the Flash code.
+ * @return {object} A Flash DOM element.
+ */
+minplayer.players.flash.getFlash = function(params) {
+  // Get the protocol.
+  var protocol = window.location.protocol;
+  if (protocol.charAt(protocol.length - 1) == ':') {
+    protocol = protocol.substring(0, protocol.length - 1);
+  }
+
+  // Convert the flashvars object to a string...
+  var flashVars = jQuery.param(params.flashvars);
+
+  // Set the codebase.
+  var codebase = protocol + '://fpdownload.macromedia.com';
+  codebase += '/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0';
+
+  // Get the HTML flash object string.
+  var flash = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
+  flash += 'codebase="' + codebase + '" ';
+  flash += 'playerType="flash" ';
+  flash += 'width="' + params.width + '" ';
+  flash += 'height="' + params.height + '" ';
+  flash += 'id="' + params.id + '" ';
+  flash += 'name="' + params.id + '"> ';
+  flash += '<param name="allowScriptAccess" value="always"></param>';
+  flash += '<param name="allowfullscreen" value="true" />';
+  flash += '<param name="movie" value="' + params.swf + '"></param>';
+  flash += '<param name="wmode" value="' + params.wmode + '"></param>';
+  flash += '<param name="quality" value="high"></param>';
+  flash += '<param name="FlashVars" value="' + flashVars + '"></param>';
+  flash += '<embed src="' + params.swf + '" ';
+  flash += 'quality="high" ';
+  flash += 'width="' + params.width + '" height="' + params.height + '" ';
+  flash += 'id="' + params.id + '" name="' + params.id + '" ';
+  flash += 'swLiveConnect="true" allowScriptAccess="always" ';
+  flash += 'wmode="' + params.wmode + '"';
+  flash += 'allowfullscreen="true" type="application/x-shockwave-flash" ';
+  flash += 'FlashVars="' + flashVars + '" ';
+  flash += 'pluginspage="' + protocol;
+  flash += '://www.macromedia.com/go/getflashplayer" />';
+  flash += '</object>';
+  return flash;
+};
+
+/**
+ * @see minplayer.players.base#playerFound
+ * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
+ */
+minplayer.players.flash.prototype.playerFound = function() {
+  return (this.display.find('object[playerType="flash"]').length > 0);
+};
+
+/**
+ * @see minplayer.players.base#getPlayer
+ * @return {object} The media player object.
+ */
+minplayer.players.flash.prototype.getPlayer = function() {
+  // IE needs the object, everyone else just needs embed.
+  var object = jQuery.browser.msie ? 'object' : 'embed';
+  return jQuery(object, this.display).eq(0)[0];
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The Flash media player class to control the flash fallback.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.minplayer = function(context, options, queue) {
+
+  // Derive from players flash.
+  minplayer.players.flash.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.flash. */
+minplayer.players.minplayer.prototype = new minplayer.players.flash();
+
+/** Reset the constructor. */
+minplayer.players.minplayer.prototype.constructor = minplayer.players.minplayer;
+
+/**
+ * Called when the Flash player is ready.
+ *
+ * @param {string} id The media player ID.
+ */
+window.onFlashPlayerReady = function(id) {
+  var media = minplayer.get(id, 'media');
+  if (media) {
+    media.onReady();
+  }
+};
+
+/**
+ * Called when the Flash player updates.
+ *
+ * @param {string} id The media player ID.
+ * @param {string} eventType The event type that was triggered.
+ */
+window.onFlashPlayerUpdate = function(id, eventType) {
+  var media = minplayer.get(id, 'media');
+  if (media) {
+    media.onMediaUpdate(eventType);
+  }
+};
+
+/**
+ * Used to debug from the Flash player to the browser console.
+ *
+ * @param {string} debug The debug string.
+ */
+window.onFlashPlayerDebug = function(debug) {
+  minplayer.console.log(debug);
+};
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.minplayer.getPriority = function() {
+  return 1;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.minplayer.canPlay = function(file) {
+  switch (file.mimetype) {
+    case 'video/mp4':
+    case 'video/x-mp4':
+    case 'video/m4v':
+    case 'video/x-m4v':
+    case 'video/x-webm':
+    case 'video/webm':
+    case 'application/octet-stream':
+    case 'video/quicktime':
+    case 'video/3gpp2':
+    case 'video/3gpp':
+    case 'application/x-shockwave-flash':
+    case 'audio/mpeg':
+    case 'audio/mp4':
+    case 'audio/aac':
+    case 'audio/vnd.wave':
+    case 'audio/x-ms-wma':
+      return true;
+
+    default:
+      return false;
+  }
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.minplayer.prototype.create = function() {
+
+  // Make sure we provide default options...
+  this.options = jQuery.extend({
+    swfplayer: 'flash/minplayer.swf'
+  }, this.options);
+
+  minplayer.players.flash.prototype.create.call(this);
+
+  // The flash variables for this flash player.
+  var flashVars = {
+    'id': this.options.id,
+    'debug': this.options.debug,
+    'config': 'nocontrols',
+    'file': this.mediaFile.path,
+    'autostart': this.options.autoplay
+  };
+
+  // Return a flash media player object.
+  return minplayer.players.flash.getFlash({
+    swf: this.options.swfplayer,
+    id: this.options.id + '_player',
+    width: this.options.width,
+    height: '100%',
+    flashvars: flashVars,
+    wmode: this.options.wmode
+  });
+};
+
+/**
+ * Called when the Flash player has an update.
+ *
+ * @param {string} eventType The event that was triggered in the player.
+ */
+minplayer.players.minplayer.prototype.onMediaUpdate = function(eventType) {
+  switch (eventType) {
+    case 'mediaMeta':
+      this.onLoaded();
+      break;
+    case 'mediaPlaying':
+      this.onPlaying();
+      break;
+    case 'mediaPaused':
+      this.onPaused();
+      break;
+    case 'mediaComplete':
+      this.onComplete();
+      break;
+  }
+};
+
+/**
+ * @see minplayer.players.base#load
+ */
+minplayer.players.minplayer.prototype.load = function(file) {
+  minplayer.players.flash.prototype.load.call(this, file);
+  if (file && this.isReady()) {
+    this.player.loadMedia(file.path, file.stream);
+  }
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.minplayer.prototype.play = function() {
+  minplayer.players.flash.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.playMedia();
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.minplayer.prototype.pause = function() {
+  minplayer.players.flash.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.pauseMedia();
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.minplayer.prototype.stop = function() {
+  minplayer.players.flash.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.stopMedia();
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.minplayer.prototype.seek = function(pos) {
+  minplayer.players.flash.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.seekMedia(pos);
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.minplayer.prototype.setVolume = function(vol) {
+  minplayer.players.flash.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.player.setVolume(vol);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.minplayer.prototype.getVolume = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVolume());
+  }
+};
+
+/**
+ * @see minplayer.players.flash#getDuration
+ */
+minplayer.players.minplayer.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+
+    // Check to see if it is immediately available.
+    var duration = this.player.getDuration();
+    if (duration) {
+      callback(duration);
+    }
+    else {
+
+      // If not, then poll every second for the duration.
+      this.poll((function(player) {
+        return function() {
+          duration = player.player.getDuration();
+          if (duration) {
+            callback(duration);
+          }
+          return !duration;
+        };
+      })(this), 1000);
+    }
+  }
+};
+
+/**
+ * @see minplayer.players.base#getCurrentTime
+ */
+minplayer.players.minplayer.prototype.getCurrentTime = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getCurrentTime());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesLoaded
+ */
+minplayer.players.minplayer.prototype.getBytesLoaded = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getMediaBytesLoaded());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesTotal.
+ */
+minplayer.players.minplayer.prototype.getBytesTotal = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getMediaBytesTotal());
+  }
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.players.base
+ * @class The YouTube media player.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.youtube = function(context, options, queue) {
+
+  /** The quality of the YouTube stream. */
+  this.quality = 'default';
+
+  // Derive from players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.youtube.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.youtube.prototype.constructor = minplayer.players.youtube;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.youtube.getPriority = function() {
+  return 10;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.youtube.canPlay = function(file) {
+
+  // Check for the mimetype for youtube.
+  if (file.mimetype === 'video/youtube') {
+    return true;
+  }
+
+  // If the path is a YouTube path, then return true.
+  return (file.path.search(/^http(s)?\:\/\/(www\.)?youtube\.com/i) === 0);
+};
+
+/**
+ * Return the ID for a provided media file.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {string} The ID for the provided media.
+ */
+minplayer.players.youtube.getMediaId = function(file) {
+  var regex = /^http[s]?\:\/\/(www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9]+)/i;
+  if (file.path.search(regex) === 0) {
+    return file.path.match(regex)[2];
+  }
+  else {
+    return file.path;
+  }
+};
+
+/**
+ * Register this youtube player so that multiple players can be present
+ * on the same page without event collision.
+ */
+minplayer.players.youtube.prototype.register = function() {
+
+  /**
+   * Register the standard youtube api ready callback.
+   */
+  window.onYouTubePlayerAPIReady = function() {
+
+    // Iterate over each media player.
+    jQuery.each(minplayer.get(null, 'player'), function(id, player) {
+
+      // Make sure this is the youtube player.
+      if (player.currentPlayer == 'youtube') {
+
+        // Create a new youtube player object for this instance only.
+        var playerId = id + '-player';
+
+        // Set this players media.
+        player.media.player = new YT.Player(playerId, {
+          events: {
+            'onReady': function(event) {
+              player.media.onReady(event);
+            },
+            'onStateChange': function(event) {
+              player.media.onPlayerStateChange(event);
+            },
+            'onPlaybackQualityChange': function(newQuality) {
+              player.media.onQualityChange(newQuality);
+            },
+            'onError': function(errorCode) {
+              player.media.onError(errorCode);
+            }
+          }
+        });
+      }
+    });
+  }
+};
+
+/**
+ * Translates the player state for the YouTube API player.
+ *
+ * @param {number} playerState The YouTube player state.
+ */
+minplayer.players.youtube.prototype.setPlayerState = function(playerState) {
+  switch (playerState) {
+    case YT.PlayerState.CUED:
+      break;
+    case YT.PlayerState.BUFFERING:
+      this.onWaiting();
+      break;
+    case YT.PlayerState.PAUSED:
+      this.onPaused();
+      break;
+    case YT.PlayerState.PLAYING:
+      this.onPlaying();
+      break;
+    case YT.PlayerState.ENDED:
+      this.onComplete();
+      break;
+    default:
+      break;
+  }
+};
+
+/**
+ * Called when an error occurs.
+ *
+ * @param {string} event The onReady event that was triggered.
+ */
+minplayer.players.youtube.prototype.onReady = function(event) {
+  minplayer.players.base.prototype.onReady.call(this);
+  this.onLoaded();
+};
+
+/**
+ * Checks to see if this player can be found.
+ * @return {bool} TRUE - Player is found, FALSE - otherwise.
+ */
+minplayer.players.youtube.prototype.playerFound = function() {
+  var iframe = this.display.find('iframe#' + this.options.id + '-player');
+  return (iframe.length > 0);
+};
+
+/**
+ * Called when the player state changes.
+ *
+ * @param {object} event A JavaScript Event.
+ */
+minplayer.players.youtube.prototype.onPlayerStateChange = function(event) {
+  this.setPlayerState(event.data);
+};
+
+/**
+ * Called when the player quality changes.
+ *
+ * @param {string} newQuality The new quality for the change.
+ */
+minplayer.players.youtube.prototype.onQualityChange = function(newQuality) {
+  this.quality = newQuality.data;
+};
+
+/**
+ * Determines if the player should show the playloader.
+ *
+ * @return {bool} If this player implements its own playLoader.
+ */
+minplayer.players.youtube.prototype.hasPlayLoader = function() {
+  return true;
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.youtube.prototype.create = function() {
+  minplayer.players.base.prototype.create.call(this);
+
+  // Insert the YouTube iframe API player.
+  var tag = document.createElement('script');
+  tag.src = 'http://www.youtube.com/player_api?enablejsapi=1';
+  var firstScriptTag = document.getElementsByTagName('script')[0];
+  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+
+  // Now register this player.
+  this.register();
+
+  // Create the iframe for this player.
+  var iframe = document.createElement('iframe');
+  iframe.setAttribute('id', this.options.id + '-player');
+  iframe.setAttribute('type', 'text/html');
+  iframe.setAttribute('width', '100%');
+  iframe.setAttribute('height', '100%');
+  iframe.setAttribute('frameborder', '0');
+
+  // Get the source.
+  var src = 'http://www.youtube.com/embed/';
+  src += this.mediaFile.id + '?';
+
+  // Determine the origin of this script.
+  var origin = location.protocol;
+  origin += '//' + location.hostname;
+  origin += (location.port && ':' + location.port);
+
+  // Add the parameters to the src.
+  src += jQuery.param({
+    'wmode': 'opaque',
+    'controls': 0,
+    'enablejsapi': 1,
+    'origin': origin,
+    'autoplay': this.options.autoplay,
+    'loop': this.options.loop
+  });
+
+  // Set the source of the iframe.
+  iframe.setAttribute('src', src);
+
+  // Return the player.
+  return iframe;
+};
+
+/**
+ * @see minplayer.players.base#load
+ */
+minplayer.players.youtube.prototype.load = function(file) {
+  minplayer.players.base.prototype.load.call(this, file);
+  if (file && this.isReady()) {
+    this.player.loadVideoById(file.id, 0, this.quality);
+  }
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.youtube.prototype.play = function() {
+  minplayer.players.base.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.playVideo();
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.youtube.prototype.pause = function() {
+  minplayer.players.base.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.pauseVideo();
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.youtube.prototype.stop = function() {
+  minplayer.players.base.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.stopVideo();
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.youtube.prototype.seek = function(pos) {
+  minplayer.players.base.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.seekTo(pos, true);
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.youtube.prototype.setVolume = function(vol) {
+  minplayer.players.base.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.player.setVolume(vol * 100);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.youtube.prototype.getVolume = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVolume());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getDuration.
+ */
+minplayer.players.youtube.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getDuration());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getCurrentTime
+ */
+minplayer.players.youtube.prototype.getCurrentTime = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getCurrentTime());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesStart.
+ */
+minplayer.players.youtube.prototype.getBytesStart = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVideoStartBytes());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesLoaded.
+ */
+minplayer.players.youtube.prototype.getBytesLoaded = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVideoBytesLoaded());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesTotal.
+ */
+minplayer.players.youtube.prototype.getBytesTotal = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVideoBytesTotal());
+  }
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.players.base
+ * @class The vimeo media player.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.vimeo = function(context, options, queue) {
+
+  // Derive from players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.vimeo.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.vimeo.prototype.constructor = minplayer.players.vimeo;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.vimeo.getPriority = function() {
+  return 10;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.vimeo.canPlay = function(file) {
+
+  // Check for the mimetype for vimeo.
+  if (file.mimetype === 'video/vimeo') {
+    return true;
+  }
+
+  // If the path is a vimeo path, then return true.
+  return (file.path.search(/^http(s)?\:\/\/(www\.)?vimeo\.com/i) === 0);
+};
+
+/**
+ * Return the ID for a provided media file.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {string} The ID for the provided media.
+ */
+minplayer.players.vimeo.getMediaId = function(file) {
+  var regex = /^http[s]?\:\/\/(www\.)?vimeo\.com\/(\?v\=)?([0-9]+)/i;
+  if (file.path.search(regex) === 0) {
+    return file.path.match(regex)[3];
+  }
+  else {
+    return file.path;
+  }
+};
+
+/**
+ * @see minplayer.players.base#reset
+ */
+minplayer.players.vimeo.prototype.reset = function() {
+
+  // Reset the flash variables..
+  minplayer.players.base.prototype.reset.call(this);
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.vimeo.prototype.create = function() {
+  minplayer.players.base.prototype.create.call(this);
+
+  // Insert the Vimeo Froogaloop player.
+  var tag = document.createElement('script');
+  tag.src = 'http://a.vimeocdn.com/js/froogaloop2.min.js';
+  var firstScriptTag = document.getElementsByTagName('script')[0];
+  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+
+  // Create the iframe for this player.
+  var iframe = document.createElement('iframe');
+  iframe.setAttribute('id', this.options.id + '-player');
+  iframe.setAttribute('type', 'text/html');
+  iframe.setAttribute('width', '100%');
+  iframe.setAttribute('height', '100%');
+  iframe.setAttribute('frameborder', '0');
+
+  // Get the source.
+  var src = 'http://player.vimeo.com/video/';
+  src += this.mediaFile.id + '?';
+
+  // Add the parameters to the src.
+  src += jQuery.param({
+    'wmode': 'opaque',
+    'api': 1,
+    'player_id': this.options.id + '-player',
+    'title': 0,
+    'byline': 0,
+    'portrait': 0,
+    'autoplay': this.options.autoplay,
+    'loop': this.options.loop
+  });
+
+  // Set the source of the iframe.
+  iframe.setAttribute('src', src);
+
+  // Now register this player when the froogaloop code is loaded.
+  this.poll((function(player) {
+    return function() {
+      if (window.Froogaloop) {
+        player.player = window.Froogaloop(iframe);
+        player.player.addEvent('ready', function() {
+          player.onReady();
+        });
+      }
+      return !window.Froogaloop;
+    };
+  })(this), 200);
+
+  // Trigger that the load has started.
+  this.trigger('loadstart');
+
+  // Return the player.
+  return iframe;
+};
+
+/**
+ * @see minplayer.players.base#onReady
+ */
+minplayer.players.vimeo.prototype.onReady = function(player_id) {
+
+  // Add the other listeners.
+  this.player.addEvent('loadProgress', (function(player) {
+    return function(progress) {
+      player.duration.set(parseFloat(progress.duration));
+      player.bytesLoaded.set(progress.bytesLoaded);
+      player.bytesTotal.set(progress.bytesTotal);
+    };
+  })(this));
+
+  this.player.addEvent('playProgress', (function(player) {
+    return function(progress) {
+      player.duration.set(parseFloat(progress.duration));
+      player.currentTime.set(parseFloat(progress.seconds));
+    };
+  })(this));
+
+  this.player.addEvent('play', (function(player) {
+    return function() {
+      player.onPlaying();
+    };
+  })(this));
+
+  this.player.addEvent('pause', (function(player) {
+    return function() {
+      player.onPaused();
+    };
+  })(this));
+
+  this.player.addEvent('finish', (function(player) {
+    return function() {
+      player.onComplete();
+    };
+  })(this));
+
+  minplayer.players.base.prototype.onReady.call(this);
+  this.onLoaded();
+};
+
+/**
+ * Checks to see if this player can be found.
+ * @return {bool} TRUE - Player is found, FALSE - otherwise.
+ */
+minplayer.players.vimeo.prototype.playerFound = function() {
+  var iframe = this.display.find('iframe#' + this.options.id + '-player');
+  return (iframe.length > 0);
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.vimeo.prototype.play = function() {
+  minplayer.players.base.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.api('play');
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.vimeo.prototype.pause = function() {
+  minplayer.players.base.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.api('pause');
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.vimeo.prototype.stop = function() {
+  minplayer.players.base.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.api('unload');
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.vimeo.prototype.seek = function(pos) {
+  minplayer.players.base.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.api('seekTo', pos);
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.vimeo.prototype.setVolume = function(vol) {
+  minplayer.players.base.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.volume.set(vol);
+    this.player.api('setVolume', vol);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.vimeo.prototype.getVolume = function(callback) {
+  this.player.api('getVolume', function(vol) {
+    callback(vol);
+  });
+};
+
+/**
+ * @see minplayer.players.base#getDuration.
+ */
+minplayer.players.vimeo.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+    if (this.duration.value) {
+      callback(this.duration.value);
+    }
+    else {
+      this.player.api('getDuration', function(duration) {
+        callback(duration);
+      });
+    }
+  }
+};
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class This is the base minplayer controller.  Other controllers can derive
+ * from the base and either build on top of it or simply define the elements
+ * that this base controller uses.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer.controller = function(context, options) {
+
+  // Derive from display
+  minplayer.display.call(this, 'controller', context, options);
+};
+
+/** Derive from minplayer.display. */
+minplayer.controller.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.controller.prototype.constructor = minplayer.controller;
+
+/**
+ * A static function that will format a time value into a string time format.
+ *
+ * @param {integer} time An integer value of time.
+ * @return {string} A string representation of the time.
+ */
+minplayer.formatTime = function(time) {
+  time = time || 0;
+  var seconds = 0, minutes = 0, hour = 0, timeString = '';
+
+  hour = Math.floor(time / 3600);
+  time -= (hour * 3600);
+  minutes = Math.floor(time / 60);
+  time -= (minutes * 60);
+  seconds = Math.floor(time % 60);
+
+  if (hour) {
+    timeString += String(hour);
+    timeString += ':';
+  }
+
+  timeString += (minutes >= 10) ? String(minutes) : ('0' + String(minutes));
+  timeString += ':';
+  timeString += (seconds >= 10) ? String(seconds) : ('0' + String(seconds));
+  return {time: timeString, units: ''};
+};
+
+/**
+ * @see minplayer.display#getElements
+ * @return {object} The elements defined by this display.
+ */
+minplayer.controller.prototype.getElements = function() {
+  var elements = minplayer.display.prototype.getElements.call(this);
+  return jQuery.extend(elements, {
+    play: null,
+    pause: null,
+    fullscreen: null,
+    seek: null,
+    progress: null,
+    volume: null,
+    timer: null
+  });
+};
+
+/**
+ * @see minplayer.plugin#construct
+ */
+minplayer.controller.prototype.construct = function() {
+
+  // Call the minplayer plugin constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Keep track of if we are dragging...
+  this.dragging = false;
+
+  // If they have a seek bar.
+  if (this.elements.seek) {
+
+    // Create the seek bar slider control.
+    this.seekBar = this.elements.seek.slider({
+      range: 'min'
+    });
+  }
+
+  // If they have a volume bar.
+  if (this.elements.volume) {
+
+    // Create the volume bar slider control.
+    this.volumeBar = this.elements.volume.slider({
+      range: 'min',
+      orientation: 'vertical'
+    });
+  }
+
+  // Get the player plugin.
+  this.get('player', function(player) {
+
+    // If they have a fullscreen button.
+    if (this.elements.fullscreen) {
+
+      // Bind to the click event.
+      this.elements.fullscreen.unbind().bind('click', function(e) {
+
+        // Toggle fullscreen mode.
+        player.toggleFullScreen();
+      }).css({'pointer' : 'hand'});
+    }
+  });
+
+  // Get the media plugin.
+  this.get('media', function(media) {
+
+    // If they have a pause button
+    if (this.elements.pause) {
+
+      // Bind to the click on this button.
+      this.elements.pause.unbind().bind('click', (function(controller) {
+        return function(event) {
+          event.preventDefault();
+          controller.playPause(false, media);
+        };
+      })(this));
+
+      // Bind to the pause event of the media.
+      media.bind('pause', (function(controller) {
+        return function(event) {
+          controller.setPlayPause(true);
+        };
+      })(this));
+    }
+
+    // If they have a play button
+    if (this.elements.play) {
+
+      // Bind to the click on this button.
+      this.elements.play.unbind().bind('click', (function(controller) {
+        return function(event) {
+          event.preventDefault();
+          controller.playPause(true, media);
+        };
+      })(this));
+
+      // Bind to the play event of the media.
+      media.bind('playing', (function(controller) {
+        return function(event) {
+          controller.setPlayPause(false);
+        };
+      })(this));
+    }
+
+    // If they have a duration, then trigger on duration change.
+    if (this.elements.duration) {
+
+      // Bind to the duration change event.
+      media.bind('durationchange', (function(controller) {
+        return function(event, data) {
+          controller.setTimeString('duration', data.duration);
+        };
+      })(this));
+
+      // Set the timestring to the duration.
+      media.getDuration((function(controller) {
+        return function(duration) {
+          controller.setTimeString('duration', duration);
+        };
+      })(this));
+    }
+
+    // If they have a progress element.
+    if (this.elements.progress) {
+
+      // Bind to the progress event.
+      media.bind('progress', (function(controller) {
+        return function(event, data) {
+          var percent = data.total ? (data.loaded / data.total) * 100 : 0;
+          controller.elements.progress.width(percent + '%');
+        };
+      })(this));
+    }
+
+    // If they have a seek bar or timer, bind to the timeupdate.
+    if (this.seekBar || this.elements.timer) {
+
+      // Bind to the time update event.
+      media.bind('timeupdate', (function(controller) {
+        return function(event, data) {
+          if (!controller.dragging) {
+            var value = 0;
+            if (data.duration) {
+              value = (data.currentTime / data.duration) * 100;
+            }
+
+            // Update the seek bar if it exists.
+            if (controller.seekBar) {
+              controller.seekBar.slider('option', 'value', value);
+            }
+
+            controller.setTimeString('timer', data.currentTime);
+          }
+        };
+      })(this));
+    }
+
+    // If they have a seekBar element.
+    if (this.seekBar) {
+
+      // Register the events for the control bar to control the media.
+      this.seekBar.slider({
+        start: (function(controller) {
+          return function(event, ui) {
+            controller.dragging = true;
+          };
+        })(this),
+        stop: (function(controller) {
+          return function(event, ui) {
+            controller.dragging = false;
+            media.getDuration(function(duration) {
+              media.seek((ui.value / 100) * duration);
+            });
+          };
+        })(this),
+        slide: (function(controller) {
+          return function(event, ui) {
+            media.getDuration(function(duration) {
+              var time = (ui.value / 100) * duration;
+              if (!controller.dragging) {
+                media.seek(time);
+              }
+              controller.setTimeString('timer', time);
+            });
+          };
+        })(this)
+      });
+    }
+
+    // Setup the volume bar.
+    if (this.volumeBar) {
+
+      // Create the slider.
+      this.volumeBar.slider({
+        slide: function(event, ui) {
+          media.setVolume(ui.value / 100);
+        }
+      });
+
+      media.bind('volumeupdate', (function(controller) {
+        return function(event, vol) {
+          controller.volumeBar.slider('option', 'value', (vol * 100));
+        };
+      })(this));
+
+      // Set the volume to match that of the player.
+      media.getVolume((function(controller) {
+        return function(vol) {
+          controller.volumeBar.slider('option', 'value', (vol * 100));
+        };
+      })(this));
+    }
+  });
+
+  // We are now ready.
+  this.ready();
+};
+
+/**
+ * Sets the play and pause state of the control bar.
+ *
+ * @param {boolean} state TRUE - Show Play, FALSE - Show Pause.
+ */
+minplayer.controller.prototype.setPlayPause = function(state) {
+  var css = '';
+  if (this.elements.play) {
+    css = state ? 'inherit' : 'none';
+    this.elements.play.css('display', css);
+  }
+  if (this.elements.pause) {
+    css = state ? 'none' : 'inherit';
+    this.elements.pause.css('display', css);
+  }
+};
+
+/**
+ * Plays or pauses the media.
+ *
+ * @param {bool} state true => play, false => pause.
+ * @param {object} media The media player object.
+ */
+minplayer.controller.prototype.playPause = function(state, media) {
+  var type = state ? 'play' : 'pause';
+  this.display.trigger(type);
+  this.setPlayPause(!state);
+  if (media) {
+    media[type]();
+  }
+};
+
+/**
+ * Sets the time string on the control bar.
+ *
+ * @param {string} element The name of the element to set.
+ * @param {number} time The total time amount to set.
+ */
+minplayer.controller.prototype.setTimeString = function(element, time) {
+  if (this.elements[element]) {
+    this.elements[element].text(minplayer.formatTime(time).time);
+  }
+};
diff --git a/core/modules/file/player/flash/README.txt b/core/modules/file/player/flash/README.txt
new file mode 100755
index 0000000000000000000000000000000000000000..e3515881730ad190d14670facf9558c0fdf77bc8
--- /dev/null
+++ b/core/modules/file/player/flash/README.txt
@@ -0,0 +1,12 @@
+The minplayer is a GPLv3, minimalistic, skinable, plugin based Flash media player.
+
+In addition to being a minimal Flash player, it was built with a solid API so that any
+JavaScript widget can communicate to this player easily and effectively controlling it
+from outside sources.
+
+This player was written with several objectives.
+
+ - Small and lightweight
+ - Solid plugin based system to easily build on top of this player without recompiling.
+ - Complete JavaScript API.
+ - Configurable using external XML files.
\ No newline at end of file
diff --git a/core/modules/file/player/flash/config/config.xml b/core/modules/file/player/flash/config/config.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8192ae4fd72388949c0158cb9dd5842b3c7d063c
--- /dev/null
+++ b/core/modules/file/player/flash/config/config.xml
@@ -0,0 +1,39 @@
+<config>
+   <settings>
+   </settings>
+   <plugins>
+      <plugin>
+         <definition>com.mediafront.display.media.MediaPlayer</definition>
+         <!--
+           If you wish to dyanmically load a SWF file for your plugin instead of including
+           the definition, you can do so by just providing the path to the plugin like so, and
+           then delete the "definition" parameter above.
+         -->
+         <!--<path>http://mysite.com/plugins/plugin.swf</path>-->
+         <skin>skins/%skin/mediaPlayer.swf</skin>
+         <type>mediaPlayer</type>
+         <name>mediaPlayer</name>
+         <visible>true</visible>
+      </plugin>
+      <plugin>
+         <definition>com.mediafront.display.media.controls.PlayLoader</definition>
+         <skin>skins/%skin/playLoader.swf</skin>
+         <type>playLoader</type>
+         <name>playLoader</name>
+         <visible>true</visible>
+         <dependencies>
+            <dependency>mediaPlayer</dependency>
+         </dependencies>
+      </plugin>
+      <plugin>
+         <definition>com.mediafront.display.media.controls.ControlBar</definition>
+         <skin>skins/%skin/controlBar.swf</skin>
+         <type>controlBar</type>
+         <name>controlBar</name>
+         <visible>true</visible>
+         <dependencies>
+            <dependency>mediaPlayer</dependency>
+         </dependencies>
+      </plugin>
+   </plugins>
+</config>
diff --git a/core/modules/file/player/flash/config/nocontrols.xml b/core/modules/file/player/flash/config/nocontrols.xml
new file mode 100644
index 0000000000000000000000000000000000000000..28fef65fcdc201f3a9e875d1bb44296be4e44380
--- /dev/null
+++ b/core/modules/file/player/flash/config/nocontrols.xml
@@ -0,0 +1,39 @@
+<config>
+   <settings>
+   </settings>
+   <plugins>
+      <plugin>
+         <definition>com.mediafront.display.media.MediaPlayer</definition>
+         <!--
+           If you wish to dyanmically load a SWF file for your plugin instead of including
+           the definition, you can do so by just providing the path to the plugin like so, and
+           then delete the "definition" parameter above.
+         -->
+         <!--<path>http://mysite.com/plugins/plugin.swf</path>-->
+         <skin>skins/%skin/mediaPlayer.swf</skin>
+         <type>mediaPlayer</type>
+         <name>mediaPlayer</name>
+         <visible>true</visible>
+      </plugin>
+      <plugin>
+         <definition>com.mediafront.display.media.controls.PlayLoader</definition>
+         <skin>skins/%skin/playLoader.swf</skin>
+         <type>playLoader</type>
+         <name>playLoader</name>
+         <visible>false</visible>
+         <dependencies>
+            <dependency>mediaPlayer</dependency>
+         </dependencies>
+      </plugin>
+      <plugin>
+         <definition>com.mediafront.display.media.controls.ControlBar</definition>
+         <skin>skins/%skin/controlBar.swf</skin>
+         <type>controlBar</type>
+         <name>controlBar</name>
+         <visible>false</visible>
+         <dependencies>
+            <dependency>mediaPlayer</dependency>
+         </dependencies>
+      </plugin>
+   </plugins>
+</config>
\ No newline at end of file
diff --git a/core/modules/file/player/flash/minplayer.swf b/core/modules/file/player/flash/minplayer.swf
new file mode 100644
index 0000000000000000000000000000000000000000..3d27d51b321ca95a5e43e921d64f60c27145a019
GIT binary patch
literal 16064
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
G*Ekup$I9^l

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/flash/skins/default/controlBar.swf b/core/modules/file/player/flash/skins/default/controlBar.swf
new file mode 100644
index 0000000000000000000000000000000000000000..95e2653b63bfe847e9f4cbfda5124e30fdb15e7f
GIT binary patch
literal 13678
zcmV-!HId3gS5pcAP5=OSoXxxkTvJK(D10U)xha&;LJ=@j0Vx4QrD^Cz>7XJ~0wfe6
z!4R6R8Vkx=aqVjZ1x3W(JNB*t`>wjy6?I)%b-Sx?ZVJWS{l9(h`~AM}3(n1)I%m#3
z=giz>Vkzjg0&o>zfgsG#8~~;oQ)vK!vOKYWQdk79s-##_=8vHuy8^kq)Zf#yva-^n
z(#Jz8%lGv1^YioMdwY6&yJHUbvTBK3SmiD$v$q?@Q)vhjmF3C`OXY=936F$@Inr`@
zke!`IZB<EWw^~V=hcHi?Bl5_VmUvbPOFg|j_@1O5%;X;`6A9%~S&CFzJS>>x;zbk-
z%L;g*$%A+aGO1WpR)&WV76*EM&fQC16o%U{Z@w4bo$u}L<&)y=?eFE|?>oeuKiHqo
z?<K3|REx%n<ib3mT&NZH!rboOUMb#ue=je8Zw&f&3-{sGh)eSd#nt~wxQCM$==quV
z{+mDZa=YDGS}rSA-J`r*Pf@X`L?n@yVV8QTT$-2bFP6$mgz{m+($eC>Tp_8@v&y}!
zK$<(gQdl8!7nAM{^z32$zcmTZEH?IkzR4veo?7lQd6G!{KXaF*RF{f8lSF0Ga#^kj
zv)gNeBsLb?A}g#A<weM(B`RA=g|adc$sc5=6(E^aqxcs}%H%>xt|&Te7?$=ZEX?!w
z4)+Qj6zc2C5Ao&?9_r;aba1GzU-;0WzCJ$Tp<(>sK+nI4YPID_bIVC5YqaJ4A86|(
zs?{cy73LS>cn<r&*ZL1Cc&b3_>!%*y{e7rlpHRO+URdc6%}_(UBEo(A1`qWMA2c|E
z@7Jxa_Yi7S^xvKPU$sT|cCH!~|Nq1t|El62L)ueQ_=fQylp+?3kDIb_QACiOE0TzK
zUI4?Ho;oCg7J?k0>YLX$3gf>?GdVZm@%3S^jwp`Nw$2|h_MBI$p<`;;Y>u6)M?pD1
zW&P3xF#~To2U{06y)>B+NuM#kVb%Ei>02l5l{Bxp?e*8SRR!YThW+;Rdxu}wKK&3U
z+x}(P`tiUyEdfE@T%_QQ1_+jnb>m)haCE$~v9a-TOjF0fNri>)3SaE1nRoee&B&U^
zGm<usyLj>9*sB*Vq_r0e+EP<fGycq(Gp`PHbSxB!MEz#HeS78N?4|4GFPxWtbMM}O
zg|A*#T!~-zqwk=>Kc=_dn(_UzWuf2h&X0Uu@#pOYR~I~4KDA=a(A5jBuYIugUBk3#
zWw(_HZBHt)=FOWoZsO4gTYmcKC+XtFi@)2rapT8d{`~9H+uy$kne6N3HNkiA;ELb>
z`myHR6Xt;ok4Jx{P0jjl^X_xik2@=@D&^%?ceCyoe7kn|r?<1ORAiS(9!PhMsd&}T
zvf{G%UB%W5dw!l&{<Bz=`YfX6L|63o+w8K|rT2~>Z@F1C`t7@S%gf5jmftA)d3{Wi
z(f4M%RxICi>3NdK+t&WXyf8aM*{ZmaBdJ~A4VL}&M?Cz?>qPcY2L~!lPdgsvK=~IQ
z27P--Xy{aG)|fl7-(Be{of;N)`c-pt^N{^-?p62eXZ+`n%MTp*6?@=%&dw?)Kfmf<
zGK*dw3CuWFw>ja91lOf=i}p@T+tA)>Vq((DH8tJ(DrUs+mp}h8pEX0c`(@(IQRT5$
z_Pw~U*t%@;Uzxed*N>ek3Mwcm3EH!FuQm40@rsIan}9=EYf0~aeDGlRiH{%O36~G-
zy4}@<y?XHd#G}hMY}jzp<px^#t##?)anEPWn31nDdGe;KHqXD@@U888!#}L|?cYCj
z=iOrBio5%ySnegs<j_;UJUMh|tL5SsyW0!yHCK)KY4e8@Gs@S*?f)e``a;X7Eg4rY
zT}r=r^=f9y<`njESCe;d=gm8qva)!T>(aOp4qyGsWHR48{_(-&Kg)`LSoN)!*LG~f
zUyBwkI@XoGf9Ac+nwnXEH6KNvB5B`!3IT@L3ph{7@col0`{{M;aqz}|r9i1>yFm&4
z^y#hu@J0hd5!_9`eunfr&-6+wt)VJ9@zTh^eq)}E1^C3|V7v}aw^?*L!U{lu;p22;
ze04&Yz*0btFn4^uOj<6<gW(K2OrSymSnmMDRv^F`EC7z)wmU%Va<ppB+WD>3{zi>j
znpQ1Ut#&wL2)@#Lq&YKpy}mGQ!5v$Ljw&ub;kHtB0gmamJDlTK<^D}rW%D?!k{p`A
zDv#53)z;zJ<w}dCGI9_dtXDG#$;aqrB7W)plRnZ!rq)D;R+{u9tG9_e+51!`QhH4M
zH|yBFtz-7Fj@8>b-9FY~mH%R$p4K{D&3yr9eAS0BV4^l|M*`<SL$EFdKH=B-^XGwM
ze4zeW$e+vf(>pXe4757*)jB>gaj^rA%2EThr365!Oqwsln>;O&hUWs}^5SBN8mXES
z6B`6_84d@G(IYWztR4!4lDuM(CU6W%v<}v9-U3(4M56H_LK!aUY1n&)KpOy2WJzCo
zBBo!Wc|>eZY)eVVhA&I_=GVQZr%=x9SvJ9E?txn02_nO9=4bCTk-vy(7-KYZMaZAv
zIC;gsOT&_mPxC2d$`?iC|4isl%lq-yH34OB)@*k9bL87-|Hg<FvnK5qEb;y3(Ju@A
zn^u3cSj4rMkac;EUlkuEo^?BDF;Q&w=Em^V9rKvyhMV~P6m@wnEs-<VIDwbH_MTNx
z+53%=R-1mhS{l1-g7B(wBKJ~Gc%bRp=D!G=C!@~~T%1+!Ibte(UFVeWOuz3_jZD37
zhi3$u>HQQ^{N?D}9cK>E{mNzI-!JLB;y0zeY~GQRer{gp@^g}Zv*X0J8*L9ym!GY_
za)9fH4z7A%^`2{WykN5EC;d-ZqRe4_!XKwq4P0<~=TO7`XCKa-5c$-q?%T#qac_)l
z((>;=Ke*lIcFEj~2~po~9%^RxI7S{W)jc%tFz@-2d!ZBez4*E7e8BkQ=gYp!wt4jP
z)LEw<U0W6W>Gs1*vFG1>te=`5wo>@<d6?bK5pU==;YVZ#ZjIRz`~5q6#&n7I$|K{C
zd5m_Q{eEzl^P{Et!?!<q@copjzfS(N_}H7Tr8kRyUXj^<p?4<x-Z}q2pU)pU_wMU?
z4`AV(vRkA5Dl1M0+#0`H^8Ede4-?O9IsdVs^yADwKX{AxkC>QVRaNCK+jqod(&L~%
zgW~oNocL?knDPfFd>^=5U%i-lSrRlcpz21~M7LYNm1KQka@*^0#`VJs&sk=EFP8it
z{oD3!7Juk9$Kx;vN1YL5gFAqEcJJC}2s3dP$FlhzRsEYQ5H1hr%dW-M)ISp{a60lZ
z+89eZ@xY*7RnB~HHhx(<Z0+2@M>G75jceX(63IlHNXFV!CS^@~WPN;mEdNE8tCcnF
zEo;_C7XC%nTq|p)P2f^|wa{XX$gDFWvyOsIG=hlUxvaud@$e+RS30Y5oQ_qKcx^_T
zl1K*5=nDV=%4o3fo7t8m*#Hkb^Ac%@)y^n@3TZLk?5R?m;eqLvxHOFb<c5vI1qshc
z_ageL4U(6dM^WaW^Ya`M!0p)~BP3GDGPH|NKkZB`wM8xxU#%bkrUUZ;h0~hl^my!-
zJ1B7X?%l^&s|pdp>_On$8f7Q>A))JT0Q-Z>fflptlX7Oyx^O4!QEZ!f2y5*SR$3RP
z;;Ri_-afJL+5}nUrP_*yusx7dE|*Is7^SbSX4YV|Ia*Pei*W)hLMKI}6(U&=lqao}
zXsma|*Z$c0WuS{I^j0@-O44P#cqo<1MWnGDy=dX0Cq?;IZnI5x57qd9r!}yDZv$=r
zvw=J?TILP^$-qxc9BE*us{b6dLK^_7SRA6&saXJQF;=2Msw05>^uoy;%j%=f(qdtC
zg0Q?yq~RFO<l_==4>ViglO=xn>ljKRXV!A>Q`=)I{~9y;+oj%h4uhOKBd1RPII&;5
z^^KpY8G`$>_viV%chgPhNQwsVtDIN)ygRmbO;G=}&#MD=3^bV;)ZqNX_7!$}*#)n^
z*swJ>CM2zywbwMcse<YLs!0()zdxh=#O$^YYs}I&EQqkUawBrlCu>%0gT1_laWd<x
zTQ8Che>v*z<w&N~a#D5G7vqi`J-*%eX2JTj^^q4ZFPeD6OXv4BjGd*ID?6E!hn=g-
ztBs9YxBC3k&K1bgdeHTQ&2L)|oi=_uQT);FWx@Ppq4R2yxlup<VDD>tBd<{BdwiYx
z$NIC+YpaU?sCVDfJi%_>Ot#Q<oOp#%Kd*g}l5gLK&x@ETzEZ`QH~ZL&H46WiQ{Bd~
z_n%x-y6(|}JHENbGM($MCO@$~U)A+f%TLN9k$T5wU;Q~}*gDTs76<j-9n1Hf@>bb)
zeB!#NU3}a9(OUy;zQ7DGQuPf+KiwC5^i$`Fn*5zF*2<sV|FFgPV$I%fYJx7+9R0S&
zXC6D>&+O`+wL1Beq?3;SCOh8Dh<qP6*G7MI*zB)|SuU0SXl6Qba9)tbuJ6~L8aklx
zW9`>omgR$9|Mj@`&a3P1uJ8Ku$*$&z+KorEetR*+E?07g$R8Ln{z1LrhQc>y?%&5e
z@vqpqaowarvkJcXGkkXb#-Hw523=N~Hxynousyol#o&3tp-$nEV1p-HiRVGZ-_1Rq
zv0>bpEg5%qkGpd?W9X>^rOUp3;5qDffH#$K>J5zpt{O=S=u)5%dr((y7T9rcJuFJ-
z`h8%&?(p+XLo+#=TyfOqii5UZIFNCv*72s74zi#MbdEo&tv1=jK7JuxBR@bZ@1)JO
z5PWr3B?MQU5RPOC9R5I6F_Uv;B9TNJ{W@42(*$+`3Hh;&ma5K=ek6wtR%LZY!Ks%^
z^Ye>E5xrCZnRza_G~@xJO<f^5rmi|pVZcAA%ctfcJ@(?zQXSFa63M7DYhO!+!;2Q!
zT;gF1$%^QTx6wV-Ks5sw_}`@aCl*r$6_yEew1phV9q2%8MM5tt9B!NCT&vi>W8L0J
zgBtU1)0f~u2V*|BJ|##s=)nKoprlKO;;Vb_8splx#+ay`=?3RN#tHsbXjB!*4lA%a
z%<I=yQZ5(4C!??M`sV>N5i3emTp^Md<_cjLOaTS7!fi-G&J<@I2dY1H0rfG}mKIH$
zMq5JLNIOgmr039I(03A@L@C3GDP|_J=xi7E1omR~e)czPvF>KQb9xW-KIqx#d+A5&
zU(tW4FE)5-z~W5eEZ{V7?sAL_V+{8j8XHv_tuwl3#5ImFK4$Wr$tRNorZg@NQN71w
z-0Ht55p+&AFxe6KL2zcagZ{fNlb7Z^_Yrs*mD(!1teZ<aYjsK9rw;aliB_kseKWUC
zp0<45uI7g)P?a}BX{|4O{`%Q@f4585?wFKjD==#tWHh{VT-I=>PV!{Iazb?K(45rf
z3i}P`SKc<4dql3iW~lrj?A#)sZT!v*&!Cm|4R^kZJE~Y_y{zNSxwCZ@4vV*^JI)sE
z5Bz1%m$Spos*S#Wt$*oY_3K5(`g1(qIz0Qvdb$1yB!i`#3cK6`Pnu5Ltyu6uR!C>y
zp)WHkA8l?p)>iNS_^YKwKz-i~ZX5dhezWzr&R2miubEo#1(^d+?s~>UZ=4&2iQ$IR
zo#@Z!?@k?^Z6Rr|Os-g73i)?<p2W0tN<B1Cvv<2L8hd%&_&@!NPAz&UZ>fo&XIL9G
z-PG2OffgspBWi}doLbCo7<Db%v3N@5oV=xt=82)h3~OSl$`$ZrsRG4VMA_5EC`KlB
zSy+2ET;TX;pF9*YnLWjP*A^+C1CI6$mtASJ>86k8G_NwUZJ6$Jw&mg*z3)r@D*a|l
z*Qsn+>PGth^?_XlMQPbE{M3i$PX=AUon8-Pb*aNI?%;fKX$IG(Y-k%v-GZ=27fjly
z^Pw$f;XA}_2EJh20=~D+wPO*A&Ip4li`8xNj9(b+^MkVZO`CzbrpRRkw;o2!5l|28
z<*r{PDsn7^jpKlwuz2%cW;Xb`3Us1IFmsmdSY|1J6R4X0<sehMQSJZeW6IQ8U0?^}
zP0>C||7T+uQ<t=XX)-{z6D3u#f&nHs6CfFV%(@x*yJD^Y%z2(AXI@NSRtHAq%}s7&
z70AN{j2_<@JEvr6^Kzi990%?pV>aG!R6vId=-IkC&Ph5srbwVe#q)o*Y1^E_iksQn
zMXpKZaagPlrF(zR+vJhM$_CdX3V3$%#|;ib1>s!>t5_8O#(MjvdynwkHw}@S+T#u9
zs1HdOcNlKlVI%u^{B28ifF!E_%e}S70C8G?y4v@oqG`7?q4L&@CG@2^O;0OEElA$s
z{17(Z1RCFl?wV3PX2}HsN~QqX)~_bwfK&i0mICEcZirRt(bKPUW)<E~x_q{Ac8uV{
zY8Q4|n|HGQtcP1}E=!+cGI8r~xVXQKd$BQ#5Iyz3Ip|HYPe0!=-lk*QGvn)Ebm>Eo
zo)Vd6)hq$(?<rvPaLVZ5#KA?UlCo}*5&fu6op-k`)ydNbtlNt7j?Bi>cIPJ=ojmfp
z=aw_!_1l|k7XU>$5GXh4Zp&DwZj76*99Xvg#=wrfXM@7;v>ck7bMWL_*ZZuYZ=*{$
zU5Ktn{#$@%F*{A#a(ZW@{l26C(#xmXc+)!fvMz@Y6MSFTu`?~R08I9^f=TQ1)aHR*
z`xXp3krX#`N9*zE)ht-#;u6()Y`E*}w4pPiy<Bx?o(8JC71(u;lfnkR4wml>+&hwt
z+$V#u^+u=m_PekAxkIu+cYekjp8K|zsz+9jb{%;&I$`In&1;iayKS*fEgBYZe?#N_
zh>&N88`|=$_uV6>d9f;^q3dwy#&Lm${GSeoHZ%q%^1H%LH8lo$D1Qn&wSHWnL`m{(
ztji*n@sf5P3AS5qV$|M+JVqip`f|v=O403bWyOQgo%+_EdlSHM2&do8ac-r{_E?VL
zVYw4^W2e2SHK6|BpQ&^5jH=Gf=Yh?)=jFp@7g_o9PGP_3zJ$qN@#Z7tkq5tY`6)UZ
zT1mENc@B*6qw0XUdZFt%g`^(%F+0G0!{W$_?YS5CZ0v%8+jqd=AUW&TD|2}ecX0=#
z9f-T@+WJ*;Shj!+v@OrGO<fgWk-Bn}_tup_$w*aD+SeSp`g6J{$mlYd;?OAUcslwz
z<prPuQ@k6WcG)F7yz0-`D4a{A0nTpDlbnRtN0|l^4Q7=NDOpx^9?90qgEm_`vEjE)
z&LX3y2%w18{Eh3Jjm<5tC+=^Xv1MOIYV_+3GyXby(}FGr+K(x~O>F!ocGQAG-?czX
zya$%6TbIfwR8Bd$P##7T1aZS%N^X8-_kmppw8F0dS<Vq9`ML<e`)2{%=FVH5TG*Z&
zwe$D#){x&e@@y~7o7mF!WZWAEhpve;ni_-L&Z}00i&;9h+fFLr9(TR#fs3`k;CEKB
zraeldo3C;m=#X8ifX(R&xUt7>LsUBt_OcX|x?TN>TQ2DBS|fn9D_|oG*a*%7{gtH+
z`WEbm6U)1*8=>h9(9o`y@De4krZj_RS=fHdul**}w?Rv|LT8lW^lb~Au3e3ct5r6`
zfb;d9cDrnacSpCuR*nK3`EOfdaxVhGZw8YMiMlPT8>hBRu-j}$y|aG)%k^`H)I$QR
z4HWJfCP_y#Ok6MF>WAlXI&n-xSLETddDn(8eF~>j-s8Q3zkTSwC>vv?{NnQ6{L$<~
z<^eYyX6G>cN1xjD!Fp>ODYjm*a5gUV?C@i;)A>ySMox9$n$re+H}mFW{Gs6XwjLVY
zWLJuIzVmH$2A8>QlzrSe<At)bwX4=w9;waHn?0jB!`=3g;M|lO!((Q5Of20!XWoo0
zoC0v2)CQ?duzA!H{7ksM9;VK<5zhG~P&lUnD4Sh@b^7GREynDi=@dTsN$0aCjg0Yl
zX(z_SU0iT?r~-{VWFNBjgpV)RbxXQ;(LSKGa6tEqQ8B;krf$FL?7HN&*_wTWn(rQ5
z$yQJ{IRPyq^5w<)$cJD*u^y^lu`(|HVv=zw4=Bw}zzS(#y<gb?5c%~E7*(1$=1A-6
zB)b9*8S8tOXPdfZgX#C4DP!(51J^VGGMAkZiqcJIU1xx4dMV_!SEhbN>jL(b1aMhY
zXH_2IRyx;Q9qAAEI4C9?50&qtjop!8=5}pqhR(3O>usq^7Oc6T%gow8`{<LWBjv$0
zIcpW(!SxwwiCe$OxV)|^<mPotb*AKbt|*F9fJ>~RDP{~H+s$Cyab^r_-@uGkyfxhc
za4%=h#wU0;e|Iw&B+BfHMs+w%!7C5#;-?Cfln-d>cu_=Zs{o~&0xen0U6Z=pvOGh9
zQfq)-%B@LjOBX=BDNvla?MqYABLv3<XgcKybG^yNnZ>$I%U!SH62fNTAWXFL@ZJ?I
z@nS1rD^h^NBX&!)!%(0t!$Ei{ZeGXghh>f@PBvY(Xmps_5)|4A^q6L_o^x`^`lB@_
z>mLAY`=br6)1M6N*!KibHBOV0U+y+*8Bm-#GLB0I+J@34vsF8aV<92@CSxPV1aM6N
z82aj1Yw4=<?5D>!?=`p>Wx>ju_O(JmIs6Cc6j}b#a%12f;KkI#EQgI7=3I!~FtZjY
z`>X+$T%xun&7uM&Vhd0f9lSB+<<F-(Ha`K%;YXlT`R%cmH`|op6oCD-C{~zc1n6i{
zdBmg5ZOFwGs2}r3%}iZwX_$}wR1EZq{e06tj90+kRG@4%4X#T`rKcRiej<0Fe9sk=
z@MiN5a<e%@m&4rvV7<StbF%)8q4Ho=8EbA+)%QICKbfydG5qQwqQ_85*~XJ5ObU}{
z5G79oIFCC1#G1`25(`p~UT{oDSEf^bGB>-7H?enSV?7m_q2v<RR-X~{VnzIT!QfBw
z1IrJKXUsj?c-d-e$K%WwijrHT2OoBMc1|{NmhYL}GzpiR6R4oeR@m7Pifh@xJMv2^
zYhKk2GMqRz^gf>wa^LIzYbP_y?G@J!ypW%(+*?mo>>xAk!VW;MkIWA3tY|p3UKejV
zEhuMb*>Gf<m+#IrkG(r;c#!flz~WlGrs56C;JpHvxw<YfRTdmGI;SGpXmv$rf@$TV
z0H74hqiF(^NZGt(DQi@cJxy6AT>MAP#MU9sFGoD90F#$>h_Uq<e~Wa`*E?~}&jh_W
zaTgC|Zy)X#<L@woob(U=9u<Yao#d0ll6}u@Y@=*h2D%55=Imz10E)yR54Zcr#7_8_
zD4;Y20_C@Lu5%Af1<JV{g3Jw3x;4vh0Xir?c=PF49DFUJZ1~#F$-_(N`7MiQ1+<b*
zK!48vEA9ULC|n*!0aaSmb|E!&hT{kYB(s6;dfMc1s~fnUeyCfQ^w-d2j?HoM27P_%
z=E#SEMs<*i<73@j+fg&~_>i(xfEaUJLQ|ca^gJFy(gy`)N%W1)Pit8gn-bqI-&Rxq
z?v~6vr6hind{yFoM+JH$fP1!Q!x<;)wu7mCJy<#JPbpn?4-A9GfQQ%DS0;@9`btGA
zA52eIfw@z-X?2u;8*szNfU#UWBX(4kPUny+F!gze_pl#Qc75Bm<gV?N7+=?&T~{0!
z`?j3t?C~4~s!c%?OeVhnCUoaR>w&>{s|`k<wXQ9FF;@S)LbbYm%Ge;7Xl{JB@HyYw
z`1dy>ObS#&4Rw==jVo|yz9K?*y|o^6;!c;rlI2>Vrw#U`(4BkKq1MLFo~K-p9eLT-
zzCY~uN&V8QRlD9-<}{e>qLiIB2%l%QU4?o)Z+-ow)e{P=O=BPIG->-Gd><K)+jg{{
zYpQew+8_LrbDE|(Zwl*oDCy+pVec=^yBM=A-32Jdhoyhvnj4v3oSL3E;j5<3jKK}b
z<EkeN$Y=^#y1Na@?)!u%K=`7$8BMvo`|HOZ%jlSA8V3;)@0!%R;Z?xg*)bod*N^3f
zb*Vepg_fu=c`+?9+~Zluk^DB;xq>XSPjv0NCTDQuBWAZ|>d&eplj%}GYI}=kkWa>D
z?`<otWJANYRrSp<Fn8D9oUO{;7xw)cx2k??0CZT{rnx$VmIA?eA$qAm=Cp)Wu1=?m
zByjA-2v%dW`(PJ4*Ow<Nfa>sK>Kp}n@4>&(axgb(@xx;;_Oj{@-)FsxYjG<H1J>#n
z>t8A;U)OB#adnB|lx-hHT5(no-OykMCU9|y+=Nrt@#7rZqY0lZSa2c6$mpy9lJ;Sh
z`<JYHRpst@E@VvV!%G$$zH}V5z+tHo(1!j7X>lv#R=iDlB`=@m_HzA#J5G|5U!K}=
z99UuwoMug2qZICY*NQjJ;VB0!xEB{KDqh%R)X+G?rqy!s&C@0cs*S_ry!G`Ht#=>%
z$eq^iV_o#p?$FKahvl(mWxpn?ZtRn54l4^Hh#4yq)?ALL0+$GYs=_%8w};-V{W(S3
zJreYG*|182A8ry*=GDQL0G8|3lOLY@J@|1#Sn8Ja`!(E6v2rj;5zwQm66f1k&p2^`
z?ZQb`EX#JSePy;t0nVvFuah)hp@&x`sI~&%-AN06vC$yB9!K<xkt!Qb*Q!vFyGRuC
zl*+7e_U6?Yq9FzDl9`Ti4?+YeGX_1}m<$#yd%2xik!^sd?R6@CM%rbt(KTiGog)h$
zydX>Zqel0F>YOI$Ro9IM-j6mv+D2*ZwITnm;{H3$hJ3)jU#%R|&r3&t!BK6<RU3K7
zq}C(B=DjxZYliF_pptvg?_W0ZkCk>^)tNM3POxOwm59y`&~vD_U?uXQEBRcA6E4Cy
z0r{~BkYwnVPjksB4Ky&EPI;$mSml>V>ovO+JiASc!A3nhtACl@lMm$VXm0F72F**O
z<{kJh*Q3uW6j!?QR_ck_;Uy<5rc=7ca`*VDm^o1@=77(ch3%;)&v})c2qtxJ@9K8I
z(i{Ka0PT~EL!_yd<G7Rwx2pQB;JI5+e)G#ob(wqGaBgC>`R)fNXUa2v?HObEgr82P
zo;zoqGwljF#?xAl-zM3i>qD&<0{K++5I<G@P(_U3RfOr>tR%t&6We)Y&|ctF+x}2X
zjC@!TsB?BaE?n}fL~dK4w5_wsz=RWEgF4PzFM^*$WL<Qdc9(;Z{&qTNKd7qTrMift
zjS$FoUgfgu%WrtV$^qE5%ypHE2&jTa2y476a*17*_z+l`0I^^0T5@L<=<Fkhec1&t
zk#}m}TWf=cZ)W5DK$D`+en8g{Z+88AF<_Y=@Az{HK{w6Xz9n%wKc|hdOaO*8$|m!1
z*~lO7_ojDdup~9g)j(N!13aelH$K6u?s>c}-<{Ebm)Ep&X>)H{b6s8PAf*YQe0Eym
zEo%<AEEPbLd2{*FoQ7MY@J2hW4b8o?d6a8TJ&ZcbV6WMsoL&d#4e_4d+@3A~mz*|a
zoxw`1ISa-ub;y5PjdJ6YafLU)1&`Zl&yq~%gYFC}?ZrqR<$oRKOdsR26+0Ulr@ql+
zR9G`=e*E3%jQ-s7Cs0)?E89dtcU!RNrt=ANuWU4e2aJ=QN%K7TuqH*pJR$d}84}VN
z2WaF=Fbg(Mo`5Sto;lAG8b(s;Ve5?6GcgP1nwp#k*CYk_pK5J>rN0AA@Z&_XTZ;e1
zoe7;=vca|WA)NUkbBn200t{4tUa(@E@b&T06@s+GO_u{66kM@ZUKTG{&VMtM9jIF3
zHr5?Iw{cKFLz$2Do9LAbRw#cwPrX`E&pz_d*pZCGv$sYIf7ltB*tk)Dc5^+fR50xn
zlm*}%cWG?7WlZ)DA>koQ`$bxhPF>;uY|b(K_~`&BoIN?I#=SnmzcQ>n^+BrPinNuZ
zgkq5yestXfW`bj;#SM*>UoEK`xbpUL?u?T=Spo_J7<f_92Ll6Ii~rll%Bs<h302Mw
zUe<dfpPs$82Tc8xV3V>tW%ym){wZ6Pmu`MoWY^Ez%XDH$fM}5dWqhwdjh8=;ZYgn^
zXmnWhMDe25UNDJs@acpz+#?J8GKS=s1&%B2++tuEcBE^^{>t#J)!+TG$kX)jA=gu9
z{d75IU$re0-YwE!mC%(P+T<4C9{l(i5k96$Ic+-dz!vPl9vr|CoL~Up$3Jj|f#3%2
z-~pb%2QTmj9~cC_Fc^lwQ1AnP2!KEcf?+Tm1dtBnAOkWX3$kGnd;ybT3Y?|fqZso{
zc;-9{o+ZzUXU((W@p!g8JDwAd&-3H?^ICa!wv9pKi~z#8Vcb%yTDMv^x5#n62?mXp
zjh1fx4|s%e8!bs1N%{Pb#2@e=|7zU?i6j)pUE)~l)@XUa^1R6b%L5*ymRdJRP#Thd
zBt*isZo1@`qX{Y~021)6`Ty(>V5*UnLVhkU=sD{}*-akvfyW^_6bm1Kz5WkzZwmQs
z0{lK)he8{srAl$HIN)(NwQn!9ySLe2+gsS(GgWEH8Ky&7^_grv#;yGaeFMA!n8V4Q
z!LYwmdwN^CsnNs#C%%8`eW9AUA?}rQ_de(IAKn}HJV4u9-t9HYKWP3mq%ZDKcdvY~
zw%3Jm<Gc9+x@E)t`^w%K_TOjp|I6NRZZ?oX*Yi!#$;~`3KR>>^H=jS47hGCeEaHVq
zOG?Y-A{j4QlIy`!F%0$MjVzQ%<<+GkUT`E&E9B?JBhN7NlBLDv<SErMl?Y5_;`I%e
zkE}Z*re;rv*IpiQPj%1=spH%kfY0~m^WnIWu8J`Mv@gxc3nz@^uB+vfUzVp7mWVVe
z`B-J#@IETxA64=ps+UUDnY;lQY1P=tYs)K_sZN!{ag$Cf^1LjNr@B1IBYc`v{B7zv
z1oXJ_k{pqYo-CIYO7e*iskB%ml<2CCpL>WZ$W!aIaPo~>AuY_K$LAD@a^;MOa!D?!
zoJCqKQ_)$m((*Eqs%t7P_K?ejlCnaTw>(6`GOU{%LMq9(`bVO_nyBBG$V#aci6knW
z7JVuHJrqW%RE?y{u`#sVVyQ$#Q;`i+^svIRQlUJzKqNEyCmpO@sYG5VDHo+k4a(#~
znLJ#AgCasEED=%5<kC`RmR3I@F03Nws}qrsOcxhQ3d;%@S}*I9tUZ$Ke33jsBgQC|
zi7H4rg6v={v#=}y-*7x@YL>XPj9u2lOUokXK$nTi%1cBHu~;gr6w2~wIimbR36Z59
zQ&%eK8Hk=+Ae7{bsMXSHDN!tymSU~!tU{7rAuNs#qn6`7QzEL8t7jy}H%^xvLl&hv
zyCcJ6RTfI}=&FHbZ1sJ|QC?g|Q{7uumdYt)pI%;?CzOk5Dg?DuM*2oOe;sK~5ewh{
zWD#~}UKx{|s%k`i(!DZiafncsg_Y~Z3JWEqvf@ICNKZXl9=<`?AIw;3MWHCPxUjTe
zUm5>CGEzyXni^jrk{My&^?ZY#EXU@tdW1Pr$tcwUq*$EiBs+oGlM5$`*y?jhstM|9
znMej*jj$>*IG=w*&%*wf7Yd8927?kZ+DQ?$FiSlZId(KNh4glzs5p-<mEbvvnBAwK
zbju2)l^XNQbV({!qIPphcbB291}yb2KUA(4lfLv~^&GX;?eRmooJxKLuBV-dN{hi~
z2XNTk(=3-8b{ns?g+&^srfYpedVnF7B#FxKbP3H#P2G}Ql`qBOEN`FBZ&PoY+F)<>
zn+6)h)^JF&ya!qSvoJ~Gl;rj@Jj-iP|G)9}rPI~Nov7sbCId{wGuP6F*!*3#H<`fY
zhja;@e2<ne)o&P~8ylYz9UqsKoD!Ur!Y+}LL7q$oKD(O`pTN@MrKMW*$oOvbNSuy(
z8gyt>a9m`#u9^_4%2_QbB04TQIZ8u{P^Gw*loXzv8mpB`QWXWAtdd+Rxj+#)<vBUU
zqB2%4`CE-*^8AKgo~G2P>teKoEEw`?T47n7Fpgd<lH|(^Y&Ada>G@qxaI%jlxh#6-
zlouA`N@&%)_WOTULfPSQDd9<35lO+Z;T&OJo{BuOuuLwJh-9=pY)3UMB|0`d$yg>T
z!Li?m&cIbs6`UM(B?%VGHH!yXQ}RV@wNa|-W30A9n43%fv@EBv7*9l7FGOYIvB$M*
zluRa-mFa7MDy&f=EY@&}@q|ROGEH*ki=-u*0#_o+D-<%-eThh}kuJqcAa+20Hz>sl
zL^6%CGGPhcHpn!?mQ~|9l^FJ<y$5zLu1^e21ufKQuPP}v>r>|ZyUUzOUwkqiUM_Oz
ziwsl0tCw9eTX88A$@=$YiYCjw5HH9TA~j>b|3L{`<?1L=VSa&}UZ8qI)kH-hc5<;u
zxA&<fR?qP!R&0D~a(Gt!sPH7Frkk3gLB?V%4X;=tIZLH_bYY&nfF>+1EfDHzEKn6@
z!(@^g)(gXqNF6ycD>*bNJUot8Ns6H=n(DMELwgpLp*^fhjTK_8V!Xu3kU!$n%5h|u
z>Ej4gtuo1~9}wyFnW*94+`|25Z_?GC_u?WhjjL;}&owYNG&iFGcL+C_8)_cTO~lXh
z`R2vu5_6d)#+w;1<{-<t$dW+=%(Vn@mm=;m#9fZKD-d@j;(m>|s}OfJ;;up5wTQb8
zaqAJc0ddzO?gnHTZrO+|n~>#3WVs1hHX|C+K{P#vF&ohc6H_jQX=d(dfh<}2+<sQp
zY#T~{o~@m|gQL>`J!coDtL{KIcMng#nK?~o10oQGKsp4X5)?Xt2m&z(#3U#zg2E<r
z^avV<Kt=>ICXfk1GbJco0+|zp1%WIHMn8gKMIdVe*$}8dLGTD<OCUP}*%QctU^o)U
ziC_#MkTZc?2;@pI1`>oDf!qn?K_E|p!6%RxfxHRiLlA=q<V!FH6U?Cm!;fJ26DWW{
zfdnInK*I<$oInDC6+*DX2oyn}NCHI>D4IYq1R6o0kpzk*P#l5c36wzSB@rl@Kq&-D
zCD14WjV90-0;Li9V+oW_pm7AsAW$ZOvIvw-AR&Qr2$V~pJOYUbmYC2lAoL3f{UU-j
zo?w*_NJ^kmf;E9aWdxEFsGL9*1gav?L;`(5peY1WAi{V$V(MW>&cJOZZZ(L>!A_lp
zyR&ht#qCSf5Bqo??#;(-0d5O%t3w2H5q|#)F-<AV#fZw>jPC<#!Kf{`wIb$LjBCYh
z8;ReJaXWC^iJ0?Aco$;sCg1lUrYn_cLuCd~nU+-MUW{Y!!+iU3JAm6k#5{y`9Kh``
zZbxtvVX>o_bPTtXh+v<>?KEy@a6600gTX*W<m>P6y<aq-Af%%M3<?Xs$lu^-U)|ie
z;qd$)J0v3mA$ngd0d(v{tR9$%#iGzu+GzjWNC5`P+6`053*$3R%?qh7%>VJi&|I`H
z3TP*fR3_3tbH)EFF9wUwq+&O-sZ2T$I=ZCq$RpeMs&5Mn0}hh_b9X}o7DfpA86&VU
zQ4viMIB|8r(2N3Ha|-BNAh6QY0X<6uCjC?#R;sHtfDVggrUPc?I$)qn0V5j~zCQv}
zo~mbypuZggTYDAcpt?FDuy<1R1|YC>R_Sm7a78);5!ktrx6&Pf1D66E4+K0<{LrbZ
z>!lLV)d6EY3g~(x7~q4zdJvEi<*TCMCvm#2?huu_p$HuP{2997-#-9>dmw_rL8L>5
zA@CfIV2FTxkPSvKkUVD#p#c66hQKwPgv<dVAQAyTibO{v@QFd-HG-5FNs?j_42?tJ
z7f+HC5O^e#og@U_$z&%5ftxBJMj;qP{;mneAn;8iNn`yP1`tfe!a?Z>hK)loJOhCs
z)1SeCNF9t0!{~5~j>z(77(y&9o0P)15g0d8NCKECCdZ#)1j*gRL`+Q55)(it*N{rd
zGt@yMLz)hqE~X<&CCaB$DAlNdPNz&lg>))qGAg3$P^O~sbQ)zELM&7a$RAuF5c?t;
z;(<X!<Oy3QVp9P*BLgZ>0+1gS>4c!MR78zJnN&oJLs?WrPeD0UM5N+7phMMB@+0xR
z(4p&4t(5%h?K#v9uDP`Gn>jQFZGF4uucID2mO}FIG(3yDnY26(s9w#dL-Iu{`Iyat
zvY|(t1JX4FxQ=n{y%nnv4wQz!E2L-?;zC2E(Up8<H2Iqj8d;AFl>Cg6Y&t)iJ_f7{
zSQt&GU?yiJKU3^hSs>2LcdIVQ&n$AAT2Pc(=r*~aFmt@yG*mD?v%qaqK>_9`sB{|L
z7%RnQ=Fp;blpO_n%IgKXk>u}65shw!M_?<(5~WyADb`hrrAl#W44a0{VPXTQSTbV*
zX#f@f8-uK^3)onaMH-=tjVR9WkMRd#F~+eeG#ZV0y?s6Qnrb?_2&*TjBj#a9k4B-<
zXCMq>SlF*!DK^)~A*d8P8{yPbV%WDK-UBJ)y+N75&Sr}XFrQLv62sPsmm!Wb$vVV{
zh2Jozkf-8{H`eeL_2I>3pxps<aY<3edjQGFVUR<prLd{`-In=c%M5g|Wn9uj4xmQ>
zWS5n5C|E_g&=>P^x_NCduOUT;Mz<g#>xx^-cneaiO@|Sc9Lk7PZA8KBEcGlSED;tl
zreO69Qhj`XggHz|N8s?vkhe$3kr9oY7_a;$=>dDC*a_Pd;YP)BrZha%V3j5lp_NiR
zNL+4YNHPz`ePz4rEul#VgCeX@d!Vql2k<CdtsN?*<n1scr^zPmz_<pX6J|2kVbbXF
z7$smAxZ$YF!5d9naUoLKUN9I3${=M9wZNXd=qhvQ1?I{eqF~7NY+|=+!q>4(4z0jU
znZb9+i{YaJPi4Fh=>rSWN&Qup>k93$hs-kM9eA#Wq*RB{T*GFGH+pnE6&touFW!)X
zk^Sftl}XMwGvwIiq=#_b&o0iUiYt|3#{mxD6kkQ-;2Q1NNnnNz*mGjfc40NXW;4VS
zm11`d4@Tf|luklxtk#Mg%Y}5hMk%M4()dXf4xRL@CmB!!R07sCEMS9;Q$>)GCeFm4
zdD({KvLv}IG#vS#arE!jW7<p4_|Ld_WQ-V)_lAs7Q_#ezEv4H-zCt~cfRT3OR0fcD
zb_nSjWyTi~Utrt48n8n)2=zEjRf_O%nG)(@c6)?X6QltHNofb9i2@9^$4@3vj-*0E
zl|n;8ExcGI>O|Gd4v)m?8HtAnTHhe_!W;ugQGL=tb-1e|+*w;VrjUh$ga3`8;KE^m
zNiGO6S?W^kszYJ18_9yuUJ!)kgTzzC3ZxXri>ILm2Ude{ItHQ!2yx92hl*#S0m2$p
zZx(V=^%Aq0;@S9pSbP-)GispVZm1SRDJlqS#_*RIj*Op!C`t`$07=v^Ca4%k#Lq=Q
zzWIR0pm`{MI60+(6l^T%MW=#r47zE-0V>eFhnk8(j~*%sdLj)NKZ<lWzZ+DQc`uTA
zIO*inWv*m3a8ZiGml;`;@fe~M&qu-q*uD@45H2L&<LeM`^Z@!8i`96OYRGCK4ma#i
zl1F1NXr)JMq(}Ei3)IpAwX_cfvDkK`bV&RnL?#XPx&so<N1u-~h~#u4IY+BF#Zf9=
zag>I;uU=mr9TwYG6~NO`M?HB<;{*HnR^x@iq}pIoElK$bWiLkJCCJ2_G?l#hPTe=3
z3<Hjd7T-50u%aPUJmPyYs&F7JMbmF#YI_ICvJ5pe2$zw8L&AwYusI2v_rOsk9MuD-
ziI*c1MZSwykk}O}>`D!GWgqO<8tm7-utDNgsKV8Vt-84+fHhSZnUa&xK;7E^g@0uq
z{*|bETor$OyKpHv`Jq%gi`|AN?*QeuaJ!9LE;V~KYIm%&+7Ph@Aq?Vu0EX5#l;0!?
z4uNX??e^;qfj!7Z74nuF%BAH{$ug5e%b?^?BPgi825(^8j-z@^p<Q=i8DJ|jDAzG%
zItO>%+K?KmpWe-h-#WC69eo%(G>n+fIEUtT0=c173SO)H7&si3A$5Y0X@u7p$NK&b
zD27id7(oW3F&UETf*(WXZZEok3_p@CP}7rCbOWW^9+b@z=aD((01k{81A0M-HsCQ?
z9M#Pb)r)1cHqv<oK^ewaFZQ#)4mQt7wNcAhi#e6zxcIe*T)qNu>0=I5@<pI2ed`cE
zyB@a&+}7jfkN=I)u~xqd{IE!1Pe}~I+g&!^Drm<U_8C0<Gg$B$9E=|?Rq57amje!u
zbO&79#yRLH#TnR424)QTPi9iJW{!;{|6h!5Gs8X`HvBU<;xjmsz_8W7n1wB(W1gu0
zWD!kkQ6?6N?y)H5vk^yp29Nv<j{Of7#r-FX=vs@iut<E5MG2pcnD`l-^ckG|A1q4w
zPZkkci*m?_F<uMg2L^7?_k(|rUSBYP>%S0HUtNIh->H4RGXR@^VCeIO1i<GUy}!az
M{fO~@0WEjtb5A_euK)l5

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/flash/skins/default/mediaPlayer.swf b/core/modules/file/player/flash/skins/default/mediaPlayer.swf
new file mode 100644
index 0000000000000000000000000000000000000000..9c1615357dc4e6c2df7cc34f47be17dd4c6f047e
GIT binary patch
literal 2995
zcmV;k3rzGwS5pZh6aWBtoTXPwP#eh^?$$h7qX&8b0)w$-z%LBa2rvdM4`V%SSg^c+
z*WQOfgVaK^mS(gwBfy(YmfBPvRXL<`$R#Id_m)czxuhypadOWA;aYE1PN~W*w^Sv^
z6#08byu9A6%|->&-T(jnfB&!kr)L)l8wdrSA#@I-bf_C4^hrA}AT({1%E^^<Ho9A@
zYGx8vGyN6Iswd;|ot>T7&R9%0w&IDYsj0X;8Xp}U0mO*;RI`-b5zQRvpN-lY($p*(
zYTZ(GEy~u)rrxk-`ukgIcWd=ywVD}IO8O>^74=$tSE<JnF*(lk04SL<sAB2Hnyy!8
z=NT%Rttw_Enpz!?J}~q$HBHz;sZPgVMW2$VY51QVl@s!aJUTL(SQ{Npj*TU6-Wri7
zlCpeC)<HU=%hXazilv+q27$y{Vk$Y7NG8Tc<eSIBXRs}Cy`+|(ek<V<WOO?IO7y;6
zJWIvnaMl|})y`3=7^hWQqnc$xNE3EQOT}baH)@JCtJLdNwWu(K@!b)#q8Fd+DBE<T
z%)&bzKLLJMlfbj(<!?@MtrkB*o7M^~e>2)#ds?UQ6>91YqeuZh&?=JUWw6Ciw`nPB
z=r!Axx?-4=;b;1f1Q^)fC8=trrD#REke&tUn5veNW2x*dIWs<<NsW$8OePZZ6N$0R
zt?aG&iTQ*)Ii8-5e?|02TS+fASdd%VO8<klQ=&)ObVJ=zp`O#<UF&O9MD0R58>f@l
zeRZo;YBD3=x-%h9j>>GSJ7d{Ydg5kcDt%`vGnpAbR(E;}hqUn3;C@?e3#WtYkaGV|
zIKEcJYfC!bYJ9U%lyV&&9zO5%LQ}+OwMaD@O(66f4cdg=qt=NL`vp7y@kfL{-njj*
z--P}ylFxp-hYqD6FkArmu_$7OyAA8-VmmyqU|^t4rTApa&>LE5IR$VxFgU<DurPyh
zKtMHGQk50D1s0;ijyHhLqfZWLVeUUa|J5GYvHmv{_~jl3B>Kx3GiD573>$XXmZ8H-
zm;Z!jAN})(kD8Bu&ukGu9?iKg15Y^Z2NU{wN5msXgd<1Vn1v!RP~D*0D&0ZPJ3jIw
zCn7-<W8VL@_hV)B;lJnhFygm$wIr@uhN^9mJJ6h|qPepTt;j;pJzie&*j*>KMfIAr
zLW@uZTU9FFZ`3xa;dgi?)vQ;Qr{a>Xl&Ilzh;*BEHzC6Y-$E{97`kCEI-qgH?C6yZ
zU9(~hORbv1L-rJNn;*ayJ+DI~ZA9c1R%>fvp{8t6akXx!7CrxZOwz{qb<G}aTT8x8
zmS=FCc}8^2w$fj07zP;XxZ^28NDNyhRJ7kiC-R19P*eSgN>y0dWRJ?8E39`1Y!e>9
z&eYg|nD~|zRa;YQw5n=UTGk;qsj6B({|YR58s^ru6?+HY>8kXesy))mvRF2h8cldq
zO|?{|%0#v(xKLE8_krPN7G~8d6-soovE>KeDzIpYIUa-+<7IX&s<C&r&jw{QWfKsB
zWhh13*2*eC3^=i&Olz{B!B_@>q--l{l}Utk&AtdYKBbu|9`>qAjtY%h(!-S{CxGr$
zZu!AdW-Sv`N+r8ImQ)k00M0^gBeSxSTk!yRg?`werqyOR<2}k`&EN^gp@?-u*{UgS
zO&=*L#R|RDdS{)yu;y3C;-j)W5#Ma6RZG?Qdc&;nEI5Lldx5g2SapokHK$C3jWUFX
zw04JVx1#E`^d)_V8Y#u3co#nvcGQwp5i3;Ps#yH8VpW84Ro4w1^MdQvf>xrtxw2$7
zHcjWiLEu>eI_$lpY*(O0?HY<<D%q0<pvJ#(x==$!DC^?_UC_$98={x0sMV5JYt-xs
z6tD-h+w*x#Y-mh*$C>k*bdJm5Sz_85os*b?ji4N<aq%q3&bk6UVw*a^-fvKH{&Yh~
z+DT@7#exhO?FOys+w@H8y$;Q`U9=Pf{P34r5;jnnPp30!x1~FMEAWa=|C#MWUokfF
zdLIRN#cffqQ!IARX?HAFibZyp-Bhcp_4KH{v5c9m1_;#wTbN#FWuMO0d4ULPP-a`l
zOPy8HQR6g~TD^MQG0msoey!DSEjVdzXWCF(ifx-(rwFcQU1wu{+)+HXACFimdhO{w
zryfm9ueU*=WLc+JwO_BX2#%15C*q3)y2Fw7?udXQ(e8n+Xe1GtaNq6<2=HR*3HOA$
z+F^|JtoLm66nd1NO-7Gs5j|3md>AnzX2gm#BHNLj$Zq6m<fEQ}p6`iL2nT{;L2U29
zLRe~Z;Xo(HM~J(t`&>`&`3_7j_2CO1U*KYtyTtqZT?1`{m#<vCc75oEcX-6XY!d7u
zm?M}cSRhy=E;qpv;k<<R6TXcIL4resbP%qSNL@tgCek?~^$^@k@Ogs!2);n@MdG<c
zxPF2M3BFA56@sr4-!+1-6Ffxl4T6UW9w9hJaGYS7_(usIBlsq1yG8IM!BYe$N!uF)
zPm{J85|}6W4#6pc(<GQ7!7K@$Bf+~Qcu!iuB(O;En*=WryiD+Yf^!5vAb}MUSe1g{
z$Qr?Klg>w^^B(DZOz=Adzf16Y1ivrkIq4lvDuSma0_T32lkUU3Oz;-L6{&+Kyh^wa
z2=|0=RjDRO9}Cj=As{~>_>(U7UUy*^huqlf<*<wA*%IypE|I`30J~i1%nz6%@?f72
zxg7##mj#R@_VAp=Vn=|Gvt-11eG<E4_}k!q6p#WK`Gf2-62hnru1Idwj*+(m)OBLy
zi-2yh67tu5&h15=Vh={`z3_F5&a+1!LVk1sqmGLhg^?Hy3EZU+@9Gb6cpxP5gCQbZ
zMws(>+$e+~DqgrJ1+kw;ID)%*?CJsoIo`c5uV22ZT)qoNa~#KC*q0B&5rpzrnz<{u
zaJ76b4DJ@L4v#l;*Ij^e@ggt%4DZX2hKjsQakGXgKB&1Ueo^Bn&JQgPp}nCRPjQtm
zNaY(ax^lxVd+8~Uz{uIld<>>|F^2bIH36nVIi8n?XNTt&WmhhN8J<ydqc{jY@5`IK
z{4N?Q3PbV@wqunmMd$JLKDTfe7oO;2<HAkE51|RL58Xl>k0v35XbK52#JRw)?tQtL
zO`?M9CqH_55QZ!tWZyvdhVebPe+mM}{}epBR^;>IL3#S1JabT<Jt)sDiu|7VWiwm>
zxJ~%HQRH82^366kqs%peaGx&R243^?>^yELb2c;J5a*hoF=CLnr5noZ3mf{PJp1cG
z7sD&lHf8QbdG3fZ^8ySKz+%1~3~mm;mA!)p@w03SGjpL-Fy;kuU*2CpkPG6%m<#O7
z`E<c27krOVU&RY#H^y#>+m~S~@q#Dt3p-n1Lb9R|Z0;my>p_;CN^m_`2-;~5?ukJd
z^O^l@2JeX##>e3tLhIptN45i1!e<l5u|%9rTp?_y7}D0w()Pm68gFN<;2nOL>&Ja=
z{w{uE?T%%+yDUlf5EnxWaO`|O59g9RQ{Yg0t{vswi*B^%{-Rl4WQ9}+K;5u8R8b+s
z=Et-Ao6X#txC!y`a-8H@-Ip(Y`m(TOei5935agGe*=79c%Y%aZci~}3M(#c&B-hgU
zz{Tc{CYT@3@^2mF-onkHKYtPW!{H%>(#KSf@5|9W@ns<#z6#;;7P^|*0hdjH%qp{N
zm{aE1Fs)3pVMdt&SwHh@a$hb4w})8qU2m3Gw!`r4wcZ7@@+y0*eO~FxcNT)VPMm+3
zm%zNY7bTo~h(W&11@b<S_cpVS5X2B@0gNTjaVZ3$6x;(4xyP&&-jNIM%7ypj!uxWe
z4gMbEKKobk12n`0o$?5~Tpn*H=<RKm^W}ALz@BU<bHHrpIFGlVF$=v=;m;TsW^)J6
zz{9>mFRKwS7LXknd%Vy|@`YT18PmzZI$)cYR|ZkxLQY|=BLX%`SNCO#USs1q_<QW?
pYuVWi@VWNe_9v%^UjJbdv%efr>yz^2OCWaoOThlR`!7bUfgm+|y-EN8

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/flash/skins/default/playLoader.swf b/core/modules/file/player/flash/skins/default/playLoader.swf
new file mode 100644
index 0000000000000000000000000000000000000000..521c405e9a4532b283c777b5a7a15f6d096ffe00
GIT binary patch
literal 2723
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

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/index.html b/core/modules/file/player/index.html
new file mode 100644
index 0000000000000000000000000000000000000000..c514634380eb6c3cbef7ac368de0c4d6c92e1531
--- /dev/null
+++ b/core/modules/file/player/index.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>minPlayer</title>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+
+    <!-- Include jQuery and jQuery UI -->
+    <script type='text/javascript' src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.js"></script>
+    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js"></script>
+
+    <!-- The following can be replaced by a single javascript include bin/minplayer.compressed.js -->
+    <script type="text/javascript" src="src/minplayer.compatibility.js"></script>
+    <script type="text/javascript" src="src/minplayer.flags.js"></script>
+    <script type="text/javascript" src="src/minplayer.async.js"></script>
+    <script type="text/javascript" src="src/minplayer.plugin.js"></script>
+    <script type="text/javascript" src="src/minplayer.display.js"></script>
+    <script type="text/javascript" src="src/minplayer.js"></script>
+    <script type="text/javascript" src="src/minplayer.image.js"></script>
+    <script type="text/javascript" src="src/minplayer.file.js"></script>
+    <script type="text/javascript" src="src/minplayer.playLoader.js"></script>
+    <script type="text/javascript" src="src/minplayer.players.base.js"></script>
+    <script type="text/javascript" src="src/minplayer.players.html5.js"></script>
+    <script type="text/javascript" src="src/minplayer.players.flash.js"></script>
+    <script type="text/javascript" src="src/minplayer.players.minplayer.js"></script>
+    <script type="text/javascript" src="src/minplayer.players.youtube.js"></script>
+    <script type="text/javascript" src="src/minplayer.players.vimeo.js"></script>
+    <script type="text/javascript" src="src/minplayer.controller.js"></script>
+
+    <!-- Include the template CSS and JS files. -->
+    <link rel="stylesheet" href="templates/default/css/media_player_default.css">
+    <script type="text/javascript" src="templates/default/js/minplayer.playLoader.default.js"></script>
+    <script type="text/javascript" src="templates/default/js/minplayer.controller.default.js"></script>
+    <script type="text/javascript" src="templates/default/js/minplayer.default.js"></script>
+    <script type="text/javascript">
+      $(function() {
+        $("#h264").minplayer();
+        $("#youtube").minplayer();
+        $("#youtube2").minplayer();
+        $("#vimeo").minplayer();
+      });
+    </script>
+  </head>
+  <body>
+    <h1>minPlayer</h1>
+    <p>Below are some examples of the minPlayer in action.  It is creating a common API to interact with all different types of players, including Vimeo and YouTube.</p>
+    <h2>h264 Example</h2>
+    <div style="width:500px; height:300px;">
+      <video id="h264" src="http://mediafront.org/sites/default/files/video/The_Living_Sky___Time-Lapse__HD.mp4" width="100%" height="100%"></video>
+    </div>
+    <h2>YouTube Example</h2>
+    <div style="width:500px; height:300px;">
+      <video id="youtube" src="http://www.youtube.com/watch?v=hLQl3WQQoQ0"></video>
+    </div>
+    <h2>Two YouTube Players on same page</h2>
+    <div style="width:500px; height:300px;">
+      <video id="youtube2" src="http://www.youtube.com/watch?v=dTAAsCNK7RA"></video>
+    </div>
+    <h2>Vimeo Example</h2>
+    <div style="width:500px; height:300px;">
+      <video id="vimeo" src="http://vimeo.com/5606758"></video>
+    </div>
+  </body>
+</html>
diff --git a/core/modules/file/player/makefile b/core/modules/file/player/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3e4036e0e97e2e896292f1537925171bad6f9196
--- /dev/null
+++ b/core/modules/file/player/makefile
@@ -0,0 +1,67 @@
+# To run this makefile, you must do the following.
+#
+# 1.)  Download http://closure-compiler.googlecode.com/files/compiler-latest.zip
+#      and place compiler.jar within the tools directory.
+#
+# 2.)  Install closure-linter tool at by following
+#      http://code.google.com/closure/utilities/docs/linter_howto.html
+#
+# 3.)  Download the JSDoc toolkit found at
+#      http://code.google.com/p/jsdoc-toolkit and place the jsdoc-toolkit
+#      directory within the tools directory.
+
+# Create the list of files
+files =   src/minplayer.compatibility.js\
+          src/minplayer.async.js\
+          src/minplayer.flags.js\
+          src/minplayer.plugin.js\
+          src/minplayer.display.js\
+          src/minplayer.js\
+          src/minplayer.image.js\
+          src/minplayer.file.js\
+          src/minplayer.playLoader.js\
+          src/minplayer.players.base.js\
+          src/minplayer.players.html5.js\
+          src/minplayer.players.flash.js\
+          src/minplayer.players.minplayer.js\
+          src/minplayer.players.youtube.js\
+          src/minplayer.players.vimeo.js\
+          src/minplayer.controller.js
+
+.DEFAULT_GOAL := all
+
+all: jslint js jsdoc
+
+# Perform a jsLint on all the files.
+jslint: ${files}
+	gjslint $^
+
+# Create an aggregated js file and a compressed js file.
+js: ${files}
+	@echo "Generating aggregated bin/minplayer.js file"
+	@cat > bin/minplayer.js $^
+	@echo "Generating compressed bin/minplayer.compressed file"
+	@java -jar tools/compiler.jar --js bin/minplayer.js --js_output_file bin/minplayer.compressed.js
+
+# Create the documentation from source code.
+jsdoc: ${files}
+	@echo "Generating documetation."
+	@java -jar tools/jsdoc-toolkit/jsrun.jar tools/jsdoc-toolkit/app/run.js -a -t=tools/jsdoc-toolkit/templates/jsdoc -d=doc $^
+
+# Fix the js style on all the files.
+fixjsstyle: ${files}
+	fixjsstyle $^
+
+# Install the necessary tools.
+tools:
+	apt-get install python-setuptools
+	apt-get install unzip
+	wget http://closure-compiler.googlecode.com/files/compiler-latest.zip -P tools
+	unzip tools/compiler-latest.zip -d tools
+	rm tools/compiler-latest.zip tools/COPYING tools/README
+	easy_install http://closure-linter.googlecode.com/files/closure_linter-latest.tar.gz
+	wget http://jsdoc-toolkit.googlecode.com/files/jsdoc_toolkit-2.4.0.zip -P tools
+	unzip tools/jsdoc_toolkit-2.4.0.zip -d tools
+	mv tools/jsdoc_toolkit-2.4.0/jsdoc-toolkit tools/jsdoc-toolkit
+	rm -rd tools/jsdoc_toolkit-2.4.0
+	rm tools/jsdoc_toolkit-2.4.0.zip
diff --git a/core/modules/file/player/src/minplayer.async.js b/core/modules/file/player/src/minplayer.async.js
new file mode 100644
index 0000000000000000000000000000000000000000..656aa11031b9b919faaf55b7035b378889596c44
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.async.js
@@ -0,0 +1,61 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class This class keeps track of asynchronous get requests for certain
+ * variables within the player.
+ */
+minplayer.async = function() {
+
+  /** The final value of this asynchronous variable. */
+  this.value = null;
+
+  /** The queue of callbacks to call when this value is determined. */
+  this.queue = [];
+};
+
+/**
+ * Retrieve the value of this variable.
+ *
+ * @param {function} callback The function to call when the value is determined.
+ * @param {function} pollValue The poll function to try and get the value every
+ * 1 second if the value is not set.
+ */
+minplayer.async.prototype.get = function(callback, pollValue) {
+
+  // If the value is set, then immediately call the callback, otherwise, just
+  // add it to the queue when the variable is set.
+  if (this.value !== null) {
+    callback(this.value);
+  }
+  else {
+
+    // Add this callback to the queue.
+    this.queue.push(callback);
+  }
+};
+
+/**
+ * Sets the value of an asynchronous value.
+ *
+ * @param {void} val The value to set.
+ */
+minplayer.async.prototype.set = function(val) {
+
+  // Set the value.
+  this.value = val;
+
+  // Get the callback queue length.
+  var i = this.queue.length;
+
+  // Iterate through all the callbacks and call them.
+  if (i) {
+    while (i--) {
+      this.queue[i](val);
+    }
+
+    // Reset the queue.
+    this.queue = [];
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.compatibility.js b/core/modules/file/player/src/minplayer.compatibility.js
new file mode 100644
index 0000000000000000000000000000000000000000..0a0dbf71f8274a291cd1b6beba4eca4506a421ab
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.compatibility.js
@@ -0,0 +1,101 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+// Private function to check a single element's play type.
+function checkPlayType(elem, playType) {
+  if ((typeof elem.canPlayType) === 'function') {
+    if (typeof playType === 'object') {
+      var i = playType.length;
+      var mimetype = '';
+      while (i--) {
+        mimetype = checkPlayType(elem, playType[i]);
+        if (!!mimetype) {
+          break;
+        }
+      }
+      return mimetype;
+    }
+    else {
+      var canPlay = elem.canPlayType(playType);
+      if (('no' !== canPlay) && ('' !== canPlay)) {
+        return playType;
+      }
+    }
+  }
+  return '';
+}
+
+/**
+ * @constructor
+ * @class This class is used to define the types of media that can be played
+ * within the browser.
+ * <p>
+ * <strong>Usage:</strong>
+ * <pre><code>
+ *   var playTypes = new minplayer.compatibility();
+ *
+ *   if (playTypes.videoOGG) {
+ *     console.log("This browser can play OGG video");
+ *   }
+ *
+ *   if (playTypes.videoH264) {
+ *     console.log("This browser can play H264 video");
+ *   }
+ *
+ *   if (playTypes.videoWEBM) {
+ *     console.log("This browser can play WebM video");
+ *   }
+ *
+ *   if (playTypes.audioOGG) {
+ *     console.log("This browser can play OGG audio");
+ *   }
+ *
+ *   if (playTypes.audioMP3) {
+ *     console.log("This browser can play MP3 audio");
+ *   }
+ *
+ *   if (playTypes.audioMP4) {
+ *     console.log("This browser can play MP4 audio");
+ *   }
+ * </code></pre>
+ */
+minplayer.compatibility = function() {
+  var elem = null;
+
+  // Create a video element.
+  elem = document.createElement('video');
+
+  /** Can play OGG video */
+  this.videoOGG = checkPlayType(elem, 'video/ogg');
+
+  /** Can play H264 video */
+  this.videoH264 = checkPlayType(elem, [
+    'video/mp4',
+    'video/h264'
+  ]);
+
+  /** Can play WEBM video */
+  this.videoWEBM = checkPlayType(elem, [
+    'video/x-webm',
+    'video/webm',
+    'application/octet-stream'
+  ]);
+
+  // Create an audio element.
+  elem = document.createElement('audio');
+
+  /** Can play audio OGG */
+  this.audioOGG = checkPlayType(elem, 'audio/ogg');
+
+  /** Can play audio MP3 */
+  this.audioMP3 = checkPlayType(elem, 'audio/mpeg');
+
+  /** Can play audio MP4 */
+  this.audioMP4 = checkPlayType(elem, 'audio/mp4');
+};
+
+if (!minplayer.playTypes) {
+
+  /** The compatible playtypes for this browser. */
+  minplayer.playTypes = new minplayer.compatibility();
+}
diff --git a/core/modules/file/player/src/minplayer.controller.js b/core/modules/file/player/src/minplayer.controller.js
new file mode 100644
index 0000000000000000000000000000000000000000..5db6870cf75bcc5eb66e41697242a72f246c8790
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.controller.js
@@ -0,0 +1,312 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class This is the base minplayer controller.  Other controllers can derive
+ * from the base and either build on top of it or simply define the elements
+ * that this base controller uses.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer.controller = function(context, options) {
+
+  // Derive from display
+  minplayer.display.call(this, 'controller', context, options);
+};
+
+/** Derive from minplayer.display. */
+minplayer.controller.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.controller.prototype.constructor = minplayer.controller;
+
+/**
+ * A static function that will format a time value into a string time format.
+ *
+ * @param {integer} time An integer value of time.
+ * @return {string} A string representation of the time.
+ */
+minplayer.formatTime = function(time) {
+  time = time || 0;
+  var seconds = 0, minutes = 0, hour = 0, timeString = '';
+
+  hour = Math.floor(time / 3600);
+  time -= (hour * 3600);
+  minutes = Math.floor(time / 60);
+  time -= (minutes * 60);
+  seconds = Math.floor(time % 60);
+
+  if (hour) {
+    timeString += String(hour);
+    timeString += ':';
+  }
+
+  timeString += (minutes >= 10) ? String(minutes) : ('0' + String(minutes));
+  timeString += ':';
+  timeString += (seconds >= 10) ? String(seconds) : ('0' + String(seconds));
+  return {time: timeString, units: ''};
+};
+
+/**
+ * @see minplayer.display#getElements
+ * @return {object} The elements defined by this display.
+ */
+minplayer.controller.prototype.getElements = function() {
+  var elements = minplayer.display.prototype.getElements.call(this);
+  return jQuery.extend(elements, {
+    play: null,
+    pause: null,
+    fullscreen: null,
+    seek: null,
+    progress: null,
+    volume: null,
+    timer: null
+  });
+};
+
+/**
+ * @see minplayer.plugin#construct
+ */
+minplayer.controller.prototype.construct = function() {
+
+  // Call the minplayer plugin constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Keep track of if we are dragging...
+  this.dragging = false;
+
+  // If they have a seek bar.
+  if (this.elements.seek) {
+
+    // Create the seek bar slider control.
+    this.seekBar = this.elements.seek.slider({
+      range: 'min'
+    });
+  }
+
+  // If they have a volume bar.
+  if (this.elements.volume) {
+
+    // Create the volume bar slider control.
+    this.volumeBar = this.elements.volume.slider({
+      range: 'min',
+      orientation: 'vertical'
+    });
+  }
+
+  // Get the player plugin.
+  this.get('player', function(player) {
+
+    // If they have a fullscreen button.
+    if (this.elements.fullscreen) {
+
+      // Bind to the click event.
+      this.elements.fullscreen.unbind().bind('click', function(e) {
+
+        // Toggle fullscreen mode.
+        player.toggleFullScreen();
+      }).css({'pointer' : 'hand'});
+    }
+  });
+
+  // Get the media plugin.
+  this.get('media', function(media) {
+
+    // If they have a pause button
+    if (this.elements.pause) {
+
+      // Bind to the click on this button.
+      this.elements.pause.unbind().bind('click', (function(controller) {
+        return function(event) {
+          event.preventDefault();
+          controller.playPause(false, media);
+        };
+      })(this));
+
+      // Bind to the pause event of the media.
+      media.bind('pause', (function(controller) {
+        return function(event) {
+          controller.setPlayPause(true);
+        };
+      })(this));
+    }
+
+    // If they have a play button
+    if (this.elements.play) {
+
+      // Bind to the click on this button.
+      this.elements.play.unbind().bind('click', (function(controller) {
+        return function(event) {
+          event.preventDefault();
+          controller.playPause(true, media);
+        };
+      })(this));
+
+      // Bind to the play event of the media.
+      media.bind('playing', (function(controller) {
+        return function(event) {
+          controller.setPlayPause(false);
+        };
+      })(this));
+    }
+
+    // If they have a duration, then trigger on duration change.
+    if (this.elements.duration) {
+
+      // Bind to the duration change event.
+      media.bind('durationchange', (function(controller) {
+        return function(event, data) {
+          controller.setTimeString('duration', data.duration);
+        };
+      })(this));
+
+      // Set the timestring to the duration.
+      media.getDuration((function(controller) {
+        return function(duration) {
+          controller.setTimeString('duration', duration);
+        };
+      })(this));
+    }
+
+    // If they have a progress element.
+    if (this.elements.progress) {
+
+      // Bind to the progress event.
+      media.bind('progress', (function(controller) {
+        return function(event, data) {
+          var percent = data.total ? (data.loaded / data.total) * 100 : 0;
+          controller.elements.progress.width(percent + '%');
+        };
+      })(this));
+    }
+
+    // If they have a seek bar or timer, bind to the timeupdate.
+    if (this.seekBar || this.elements.timer) {
+
+      // Bind to the time update event.
+      media.bind('timeupdate', (function(controller) {
+        return function(event, data) {
+          if (!controller.dragging) {
+            var value = 0;
+            if (data.duration) {
+              value = (data.currentTime / data.duration) * 100;
+            }
+
+            // Update the seek bar if it exists.
+            if (controller.seekBar) {
+              controller.seekBar.slider('option', 'value', value);
+            }
+
+            controller.setTimeString('timer', data.currentTime);
+          }
+        };
+      })(this));
+    }
+
+    // If they have a seekBar element.
+    if (this.seekBar) {
+
+      // Register the events for the control bar to control the media.
+      this.seekBar.slider({
+        start: (function(controller) {
+          return function(event, ui) {
+            controller.dragging = true;
+          };
+        })(this),
+        stop: (function(controller) {
+          return function(event, ui) {
+            controller.dragging = false;
+            media.getDuration(function(duration) {
+              media.seek((ui.value / 100) * duration);
+            });
+          };
+        })(this),
+        slide: (function(controller) {
+          return function(event, ui) {
+            media.getDuration(function(duration) {
+              var time = (ui.value / 100) * duration;
+              if (!controller.dragging) {
+                media.seek(time);
+              }
+              controller.setTimeString('timer', time);
+            });
+          };
+        })(this)
+      });
+    }
+
+    // Setup the volume bar.
+    if (this.volumeBar) {
+
+      // Create the slider.
+      this.volumeBar.slider({
+        slide: function(event, ui) {
+          media.setVolume(ui.value / 100);
+        }
+      });
+
+      media.bind('volumeupdate', (function(controller) {
+        return function(event, vol) {
+          controller.volumeBar.slider('option', 'value', (vol * 100));
+        };
+      })(this));
+
+      // Set the volume to match that of the player.
+      media.getVolume((function(controller) {
+        return function(vol) {
+          controller.volumeBar.slider('option', 'value', (vol * 100));
+        };
+      })(this));
+    }
+  });
+
+  // We are now ready.
+  this.ready();
+};
+
+/**
+ * Sets the play and pause state of the control bar.
+ *
+ * @param {boolean} state TRUE - Show Play, FALSE - Show Pause.
+ */
+minplayer.controller.prototype.setPlayPause = function(state) {
+  var css = '';
+  if (this.elements.play) {
+    css = state ? 'inherit' : 'none';
+    this.elements.play.css('display', css);
+  }
+  if (this.elements.pause) {
+    css = state ? 'none' : 'inherit';
+    this.elements.pause.css('display', css);
+  }
+};
+
+/**
+ * Plays or pauses the media.
+ *
+ * @param {bool} state true => play, false => pause.
+ * @param {object} media The media player object.
+ */
+minplayer.controller.prototype.playPause = function(state, media) {
+  var type = state ? 'play' : 'pause';
+  this.display.trigger(type);
+  this.setPlayPause(!state);
+  if (media) {
+    media[type]();
+  }
+};
+
+/**
+ * Sets the time string on the control bar.
+ *
+ * @param {string} element The name of the element to set.
+ * @param {number} time The total time amount to set.
+ */
+minplayer.controller.prototype.setTimeString = function(element, time) {
+  if (this.elements[element]) {
+    this.elements[element].text(minplayer.formatTime(time).time);
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.display.js b/core/modules/file/player/src/minplayer.display.js
new file mode 100644
index 0000000000000000000000000000000000000000..e926f3191f4164ebf94c0232273ee3897e38f739
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.display.js
@@ -0,0 +1,296 @@
+/** The minplayer namespace. */
+minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @extends minplayer.plugin
+ * @class Base class used to provide the display and options for any component
+ * deriving from this class.  Components who derive are expected to provide
+ * the elements that they define by implementing the getElements method.
+ *
+ * @param {string} name The name of this plugin.
+ * @param {object} context The jQuery context this component resides.
+ * @param {object} options The options for this component.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.display = function(name, context, options, queue) {
+
+  // See if we allow resize on this display.
+  this.allowResize = false;
+
+  if (context) {
+
+    // Set the display.
+    this.display = this.getDisplay(context, options);
+  }
+
+  // Derive from plugin
+  minplayer.plugin.call(this, name, context, options, queue);
+};
+
+/** Derive from minplayer.plugin. */
+minplayer.display.prototype = new minplayer.plugin();
+
+/** Reset the constructor. */
+minplayer.display.prototype.constructor = minplayer.display;
+
+/**
+ * Returns the display for this component.
+ *
+ * @param {object} context The original context.
+ * @param {object} options The options for this component.
+ * @return {object} The jQuery context for this display.
+ */
+minplayer.display.prototype.getDisplay = function(context, options) {
+  return jQuery(context);
+};
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.display.prototype.construct = function() {
+
+  // Call the plugin constructor.
+  minplayer.plugin.prototype.construct.call(this);
+
+  // Get the display elements.
+  this.elements = this.getElements();
+
+  // Only do this if they allow resize for this display.
+  if (this.allowResize) {
+
+    // Set the resize timeout and this pointer.
+    var resizeTimeout = 0;
+
+    // Add a handler to trigger a resize event.
+    jQuery(window).resize((function(display) {
+      return function() {
+        clearTimeout(resizeTimeout);
+        resizeTimeout = setTimeout(function() {
+          display.onResize();
+        }, 200);
+      };
+    })(this));
+  }
+};
+
+/**
+ * Called when the window resizes.
+ */
+minplayer.display.prototype.onResize = function() {
+};
+
+/**
+ * Gets the full screen element.
+ *
+ * @return {object} The display to be used for full screen support.
+ */
+minplayer.display.prototype.fullScreenElement = function() {
+  return this.display;
+};
+
+/**
+ * Called if you would like for your display item to show then hide.
+ *
+ * @param {object} element The element you would like to hide or show.
+ * @param {number} timeout The timeout to hide and show.
+ */
+minplayer.showThenHide = function(element, timeout) {
+
+  // Ensure we have a timeout.
+  timeout = timeout || 5000;
+
+  // If this has not yet been configured.
+  if (!element.showTimer) {
+
+    // Bind when they move the mouse.
+    jQuery(document).bind('mousemove', function() {
+      minplayer.showThenHide(element, timeout);
+    });
+  }
+
+  // Clear the timeout, and then setup the show then hide functionality.
+  clearTimeout(element.showTimer);
+
+  // Show the display.
+  element.show();
+
+  // Set a timer to hide it after the timeout.
+  element.showTimer = setTimeout(function() {
+    element.hide('slow');
+  }, timeout);
+};
+
+/**
+ * Make this display element go fullscreen.
+ *
+ * @param {boolean} full Tell the player to go into fullscreen or not.
+ */
+minplayer.display.prototype.fullscreen = function(full) {
+  var isFull = this.isFullScreen();
+  var element = this.fullScreenElement();
+  if (isFull && !full) {
+    element.removeClass('fullscreen');
+    if (screenfull) {
+      screenfull.exit();
+    }
+    this.trigger('fullscreen', false);
+  }
+  else if (!isFull && full) {
+    element.addClass('fullscreen');
+    if (screenfull) {
+      screenfull.request(element[0]);
+      screenfull.onchange = (function(display) {
+        return function(e) {
+          if (!screenfull.isFullscreen) {
+            display.fullscreen(false);
+          }
+        };
+      })(this);
+    }
+    this.trigger('fullscreen', true);
+  }
+};
+
+/**
+ * Toggle fullscreen.
+ */
+minplayer.display.prototype.toggleFullScreen = function() {
+  this.fullscreen(!this.isFullScreen());
+};
+
+/**
+ * Checks to see if we are in fullscreen mode.
+ *
+ * @return {boolean} TRUE - fullscreen, FALSE - otherwise.
+ */
+minplayer.display.prototype.isFullScreen = function() {
+  return this.fullScreenElement().hasClass('fullscreen');
+};
+
+/**
+ * Returns a scaled rectangle provided a ratio and the container rect.
+ *
+ * @param {number} ratio The width/height ratio of what is being scaled.
+ * @param {object} rect The bounding rectangle for scaling.
+ * @return {object} The Rectangle object of the scaled rectangle.
+ */
+minplayer.display.prototype.getScaledRect = function(ratio, rect) {
+  var scaledRect = {};
+  scaledRect.x = rect.x ? rect.x : 0;
+  scaledRect.y = rect.y ? rect.y : 0;
+  scaledRect.width = rect.width ? rect.width : 0;
+  scaledRect.height = rect.height ? rect.height : 0;
+  if (ratio) {
+    if ((rect.width / rect.height) > ratio) {
+      scaledRect.height = rect.height;
+      scaledRect.width = Math.floor(rect.height * ratio);
+    }
+    else {
+      scaledRect.height = Math.floor(rect.width / ratio);
+      scaledRect.width = rect.width;
+    }
+    scaledRect.x = Math.floor((rect.width - scaledRect.width) / 2);
+    scaledRect.y = Math.floor((rect.height - scaledRect.height) / 2);
+  }
+  return scaledRect;
+};
+
+/**
+ * Returns all the jQuery elements that this component uses.
+ *
+ * @return {object} An object which defines all the jQuery elements that
+ * this component uses.
+ */
+minplayer.display.prototype.getElements = function() {
+  return {};
+};
+
+/**
+ * Returns if this component is valid and exists within the DOM.
+ *
+ * @return {boolean} TRUE if the plugin display is valid.
+ */
+minplayer.display.prototype.isValid = function() {
+  return (this.display.length > 0);
+};
+
+/**
+ * From https://github.com/sindresorhus/screenfull.js
+ */
+/*global Element:true*/
+(function(window, document) {
+  'use strict';
+  var methods = (function() {
+    var methodMap = [
+      [
+        'requestFullscreen',
+        'exitFullscreen',
+        'fullscreenchange',
+        'fullscreen',
+        'fullscreenElement'
+      ],
+      [
+        'webkitRequestFullScreen',
+        'webkitCancelFullScreen',
+        'webkitfullscreenchange',
+        'webkitIsFullScreen',
+        'webkitCurrentFullScreenElement'
+      ],
+      [
+        'mozRequestFullScreen',
+        'mozCancelFullScreen',
+        'mozfullscreenchange',
+        'mozFullScreen',
+        'mozFullScreenElement'
+      ]
+    ];
+    for (var i = 0, l = methodMap.length; i < l; i++) {
+      var val = methodMap[i];
+      if (val[1] in document) {
+        return val;
+      }
+    }
+  })();
+
+  if (!methods) {
+    return window.screenfull = false;
+  }
+
+  var keyboardAllowed = 'ALLOW_KEYBOARD_INPUT' in Element;
+
+  var screenfull = {
+    init: function() {
+      document.addEventListener(methods[2], function(e) {
+        screenfull.isFullscreen = document[methods[3]];
+        screenfull.element = document[methods[4]];
+        screenfull.onchange(e);
+      });
+      return this;
+    },
+    isFullscreen: document[methods[3]],
+    element: document[methods[4]],
+    request: function(elem) {
+      elem = elem || document.documentElement;
+      elem[methods[0]](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
+      // Work around Safari 5.1 bug: reports support for keyboard in fullscreen
+      // even though it doesn't.
+      if (!document.isFullscreen) {
+        elem[methods[0]]();
+      }
+    },
+    exit: function() {
+      document[methods[1]]();
+    },
+    toggle: function(elem) {
+      if (this.isFullscreen) {
+        this.exit();
+      } else {
+        this.request(elem);
+      }
+    },
+    onchange: function() {}
+  };
+
+  window.screenfull = screenfull.init();
+})(window, document);
diff --git a/core/modules/file/player/src/minplayer.file.js b/core/modules/file/player/src/minplayer.file.js
new file mode 100644
index 0000000000000000000000000000000000000000..24c0f44f43caca2c4f0a1e110168304f516e4085
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.file.js
@@ -0,0 +1,167 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class A wrapper class used to provide all the data necessary to control an
+ * individual file within this media player.
+ *
+ * @param {object} file A media file object with minimal required information.
+ */
+minplayer.file = function(file) {
+  this.duration = file.duration || 0;
+  this.bytesTotal = file.bytesTotal || 0;
+  this.quality = file.quality || 0;
+  this.stream = file.stream || '';
+  this.path = file.path || '';
+  this.codecs = file.codecs || '';
+
+  // These should be provided, but just in case...
+  this.extension = file.extension || this.getFileExtension();
+  this.mimetype = file.mimetype || file.filemime || this.getMimeType();
+  this.type = file.type || this.getType();
+
+  // Fail safe to try and guess the mimetype and media type.
+  if (!this.type) {
+    this.mimetype = this.getMimeType();
+    this.type = this.getType();
+  }
+
+  // Get the player.
+  this.player = file.player || this.getBestPlayer();
+  this.priority = file.priority || this.getPriority();
+  this.id = file.id || this.getId();
+};
+
+/**
+ * Returns the best player for the job.
+ *
+ * @return {string} The best player to play the media file.
+ */
+minplayer.file.prototype.getBestPlayer = function() {
+  var bestplayer = null, bestpriority = 0;
+  jQuery.each(minplayer.players, (function(file) {
+    return function(name, player) {
+      var priority = player.getPriority();
+      if (player.canPlay(file) && (priority > bestpriority)) {
+        bestplayer = name;
+        bestpriority = priority;
+      }
+    };
+  })(this));
+  return bestplayer;
+};
+
+/**
+ * The priority of this file is determined by the priority of the best
+ * player multiplied by the priority of the mimetype.
+ *
+ * @return {integer} The priority of the media file.
+ */
+minplayer.file.prototype.getPriority = function() {
+  var priority = 1;
+  if (this.player) {
+    priority = minplayer.players[this.player].getPriority();
+  }
+  switch (this.mimetype) {
+    case 'video/x-webm':
+    case 'video/webm':
+    case 'application/octet-stream':
+      return priority * 10;
+    case 'video/mp4':
+    case 'audio/mp4':
+    case 'audio/mpeg':
+      return priority * 9;
+    case 'video/ogg':
+    case 'audio/ogg':
+    case 'video/quicktime':
+      return priority * 8;
+    default:
+      return priority * 5;
+  }
+};
+
+/**
+ * Returns the file extension of the file path.
+ *
+ * @return {string} The file extension.
+ */
+minplayer.file.prototype.getFileExtension = function() {
+  return this.path.substring(this.path.lastIndexOf('.') + 1).toLowerCase();
+};
+
+/**
+ * Returns the proper mimetype based off of the extension.
+ *
+ * @return {string} The mimetype of the file based off of extension.
+ */
+minplayer.file.prototype.getMimeType = function() {
+  switch (this.extension) {
+    case 'mp4': case 'm4v': case 'flv': case 'f4v':
+      return 'video/mp4';
+    case'webm':
+      return 'video/webm';
+    case 'ogg': case 'ogv':
+      return 'video/ogg';
+    case '3g2':
+      return 'video/3gpp2';
+    case '3gpp':
+    case '3gp':
+      return 'video/3gpp';
+    case 'mov':
+      return 'video/quicktime';
+    case'swf':
+      return 'application/x-shockwave-flash';
+    case 'oga':
+      return 'audio/ogg';
+    case 'mp3':
+      return 'audio/mpeg';
+    case 'm4a': case 'f4a':
+      return 'audio/mp4';
+    case 'aac':
+      return 'audio/aac';
+    case 'wav':
+      return 'audio/vnd.wave';
+    case 'wma':
+      return 'audio/x-ms-wma';
+    default:
+      return 'unknown';
+  }
+};
+
+/**
+ * The type of media this is: video or audio.
+ *
+ * @return {string} "video" or "audio" based on what the type of media this
+ * is.
+ */
+minplayer.file.prototype.getType = function() {
+  switch (this.mimetype) {
+    case 'video/mp4':
+    case 'video/webm':
+    case 'application/octet-stream':
+    case 'video/x-webm':
+    case 'video/ogg':
+    case 'video/3gpp2':
+    case 'video/3gpp':
+    case 'video/quicktime':
+      return 'video';
+    case 'audio/mp3':
+    case 'audio/mp4':
+    case 'audio/ogg':
+    case 'audio/mpeg':
+      return 'audio';
+    default:
+      return '';
+  }
+};
+
+/**
+ * Returns the ID for this media file.
+ *
+ * @return {string} The id for this media file which is provided by the player.
+ */
+minplayer.file.prototype.getId = function() {
+  var player = minplayer.players[this.player];
+  return (player && player.getMediaId) ? player.getMediaId(this) : '';
+};
diff --git a/core/modules/file/player/src/minplayer.flags.js b/core/modules/file/player/src/minplayer.flags.js
new file mode 100644
index 0000000000000000000000000000000000000000..4d97c3765a5f7dd592d917cc0543b6e484137cb4
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.flags.js
@@ -0,0 +1,71 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class This is a class used to keep track of flag states
+ * which is used to control the busy cursor, big play button, among other
+ * items in which multiple components can have an interest in hiding or
+ * showing a single element on the screen.
+ *
+ * <p>
+ * <strong>Usage:</strong>
+ * <pre><code>
+ *   // Declare a flags variable.
+ *   var flags = new minplayer.flags();
+ *
+ *   // Set the flag based on two components interested in the flag.
+ *   flags.setFlag("component1", true);
+ *   flags.setFlag("component2", true);
+ *
+ *   // Print out the value of the flags. ( Prints 3 )
+ *   console.log(flags.flags);
+ *
+ *   // Now unset a single components flag.
+ *   flags.setFlag("component1", false);
+ *
+ *   // Print out the value of the flags.
+ *   console.log(flags.flags);
+ *
+ *   // Unset the other components flag.
+ *   flags.setFlag("component2", false);
+ *
+ *   // Print out the value of the flags.
+ *   console.log(flags.flags);
+ * </code></pre>
+ * </p>
+ */
+minplayer.flags = function() {
+
+  /** The flag. */
+  this.flag = 0;
+
+  /** Id map to reference id with the flag index. */
+  this.ids = {};
+
+  /** The number of flags. */
+  this.numFlags = 0;
+};
+
+/**
+ * Sets a flag based on boolean logic operators.
+ *
+ * @param {string} id The id of the controller interested in this flag.
+ * @param {boolean} value The value of this flag ( true or false ).
+ */
+minplayer.flags.prototype.setFlag = function(id, value) {
+
+  // Define this id if it isn't present.
+  if (!this.ids.hasOwnProperty(id)) {
+    this.ids[id] = this.numFlags;
+    this.numFlags++;
+  }
+
+  // Use binary operations to keep track of the flag state
+  if (value) {
+    this.flag |= (1 << this.ids[id]);
+  }
+  else {
+    this.flag &= ~(1 << this.ids[id]);
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.image.js b/core/modules/file/player/src/minplayer.image.js
new file mode 100644
index 0000000000000000000000000000000000000000..7759673fe17853912608a717a590bac085fce3b4
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.image.js
@@ -0,0 +1,144 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @class A class to easily handle images.
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer.image = function(context, options) {
+
+  // Determine if the image is loaded.
+  this.loaded = false;
+
+  // The image loader.
+  this.loader = null;
+
+  // The ratio of the image.
+  this.ratio = 0;
+
+  // The image element.
+  this.img = null;
+
+  // Derive from display
+  minplayer.display.call(this, 'image', context, options);
+};
+
+/** Derive from minplayer.display. */
+minplayer.image.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.image.prototype.constructor = minplayer.image;
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.image.prototype.construct = function() {
+
+  // Say we need to resize.
+  this.allowResize = true;
+
+  // Call the media display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Set the container to not show any overflow...
+  this.display.css('overflow', 'hidden');
+
+  /** The loader for the image. */
+  this.loader = new Image();
+
+  /** Register for when the image is loaded within the loader. */
+  this.loader.onload = (function(image) {
+    return function() {
+      image.loaded = true;
+      image.ratio = (image.loader.width / image.loader.height);
+      image.resize();
+      image.trigger('loaded');
+    };
+  })(this);
+
+  // We are now ready.
+  this.ready();
+};
+
+/**
+ * Loads an image.
+ *
+ * @param {string} src The source of the image to load.
+ */
+minplayer.image.prototype.load = function(src) {
+
+  // First clear the previous image.
+  this.clear(function() {
+
+    // Create the new image, and append to the display.
+    this.display.empty();
+    this.img = jQuery(document.createElement('img')).attr({src: ''}).hide();
+    this.display.append(this.img);
+    this.loader.src = src;
+  });
+};
+
+/**
+ * Clears an image.
+ *
+ * @param {function} callback Called when the image is done clearing.
+ */
+minplayer.image.prototype.clear = function(callback) {
+  this.loaded = false;
+  if (this.img) {
+    this.img.fadeOut((function(image) {
+      return function() {
+        image.img.attr('src', '');
+        image.loader.src = '';
+        $(this).remove();
+        callback.call(image);
+      };
+    })(this));
+  }
+  else {
+    callback.call(this);
+  }
+};
+
+/**
+ * Resize the image provided a width and height or nothing.
+ *
+ * @param {integer} width (optional) The width of the container.
+ * @param {integer} height (optional) The height of the container.
+ */
+minplayer.image.prototype.resize = function(width, height) {
+  width = width || this.display.width();
+  height = height || this.display.height();
+  if (width && height && this.loaded) {
+
+    // Get the scaled rectangle.
+    var rect = this.getScaledRect(this.ratio, {
+      width: width,
+      height: height
+    });
+
+    // Now set this image to the new size.
+    if (this.img) {
+      this.img.attr('src', this.loader.src).css({
+        marginLeft: rect.x,
+        marginTop: rect.y,
+        width: rect.width,
+        height: rect.height
+      });
+    }
+
+    // Show the container.
+    this.img.fadeIn();
+  }
+};
+
+/**
+ * @see minplayer.display#onResize
+ */
+minplayer.image.prototype.onResize = function() {
+
+  // Resize the image to fit.
+  this.resize();
+};
diff --git a/core/modules/file/player/src/minplayer.js b/core/modules/file/player/src/minplayer.js
new file mode 100644
index 0000000000000000000000000000000000000000..f38c633f331c44e86cc6976c1bbea66aefb11374
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.js
@@ -0,0 +1,352 @@
+// Add a way to instanciate using jQuery prototype.
+if (!jQuery.fn.minplayer) {
+
+  /**
+   * @constructor
+   *
+   * Define a jQuery minplayer prototype.
+   *
+   * @param {object} options The options for this jQuery prototype.
+   * @return {Array} jQuery object.
+   */
+  jQuery.fn.minplayer = function(options) {
+    return jQuery(this).each(function() {
+      options = options || {};
+      options.id = options.id || $(this).attr('id') || Math.random();
+      if (!minplayer.plugins[options.id]) {
+        options.template = options.template || 'default';
+        if (minplayer[options.template]) {
+          new minplayer[options.template](jQuery(this), options);
+        }
+        else {
+          new minplayer(jQuery(this), options);
+        }
+      }
+    });
+  };
+}
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The core media player class which governs the media player
+ * functionality.
+ *
+ * <p><strong>Usage:</strong>
+ * <pre><code>
+ *
+ *   // Create a media player.
+ *   var player = jQuery("#player").minplayer({
+ *
+ *   });
+ *
+ * </code></pre>
+ * </p>
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer = jQuery.extend(function(context, options) {
+
+  // Derive from display
+  minplayer.display.call(this, 'player', context, options);
+}, minplayer);
+
+/** Derive from minplayer.display. */
+minplayer.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.prototype.constructor = minplayer;
+
+/**
+ * Define a way to debug.
+ */
+minplayer.console = console || {log: function(data) {}};
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.prototype.construct = function() {
+
+  // Allow them to provide arguments based off of the DOM attributes.
+  jQuery.each(this.context[0].attributes, (function(player) {
+    return function(index, attr) {
+      player.options[attr.name] = player.options[attr.name] || attr.value;
+    };
+  })(this));
+
+  // Make sure we provide default options...
+  this.options = jQuery.extend({
+    id: 'player',
+    build: false,
+    wmode: 'transparent',
+    preload: true,
+    autoplay: false,
+    loop: false,
+    width: '100%',
+    height: '350px',
+    debug: false,
+    volume: 80,
+    files: [],
+    file: '',
+    preview: '',
+    attributes: {}
+  }, this.options);
+
+  // Call the minplayer display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  /** The controller for this player. */
+  this.controller = this.create('controller');
+
+  /** The play loader for this player. */
+  this.playLoader = this.create('playLoader');
+
+  /** Variable to store the current media player. */
+  this.currentPlayer = 'html5';
+
+  // Add key events to the window.
+  this.addKeyEvents();
+
+  // Now load these files.
+  this.load(this.getFiles());
+
+  // Add the player events.
+  this.addEvents();
+
+  // The player is ready.
+  this.ready();
+};
+
+/**
+ * We need to bind to events we are interested in.
+ */
+minplayer.prototype.addEvents = function() {
+  minplayer.get.call(this, this.options.id, null, (function(player) {
+    return function(plugin) {
+
+      // Bind to the error event.
+      plugin.bind('error', function(event, data) {
+
+        // If an error occurs within the html5 media player, then try
+        // to fall back to the flash player.
+        if (player.currentPlayer == 'html5') {
+          player.options.file.player = 'minplayer';
+          player.loadPlayer();
+        }
+        else {
+          player.error(data);
+        }
+      });
+
+      // Bind to the fullscreen event.
+      plugin.bind('fullscreen', function(event, data) {
+        player.resize();
+      });
+    };
+  })(this));
+};
+
+/**
+ * Sets an error on the player.
+ *
+ * @param {string} error The error to display on the player.
+ */
+minplayer.prototype.error = function(error) {
+  error = error || '';
+  if (this.elements.error) {
+
+    // Set the error text.
+    this.elements.error.text(error);
+    if (error) {
+      this.elements.error.show();
+    }
+    else {
+      this.elements.error.hide();
+    }
+  }
+};
+
+/**
+ * Adds key events to the player.
+ */
+minplayer.prototype.addKeyEvents = function() {
+  jQuery(document).bind('keydown', (function(player) {
+    return function(event) {
+      switch (event.keyCode) {
+        case 113: // ESC
+        case 27:  // Q
+          if (player.isFullScreen()) {
+            player.fullscreen(false);
+          }
+          break;
+      }
+    };
+  })(this));
+};
+
+/**
+ * Returns all the media files available for this player.
+ *
+ * @return {array} All the media files for this player.
+ */
+minplayer.prototype.getFiles = function() {
+  var files = [];
+  var mediaSrc = null;
+
+  // Get the files involved...
+  if (this.elements.media) {
+    mediaSrc = this.elements.media.attr('src');
+    if (mediaSrc) {
+      files.push({'path': mediaSrc});
+    }
+    jQuery('source', this.elements.media).each(function() {
+      files.push({
+        'path': jQuery(this).attr('src'),
+        'mimetype': jQuery(this).attr('type'),
+        'codecs': jQuery(this).attr('codecs')
+      });
+    });
+  }
+
+  return files;
+};
+
+/**
+ * Returns the full media player object.
+ * @param {array} files An array of files to chose from.
+ * @return {object} The best media file to play in the current browser.
+ */
+minplayer.prototype.getMediaFile = function(files) {
+
+  // If there are no files then return null.
+  if (!files) {
+    return null;
+  }
+
+  // If the file is a single string, then return the file object.
+  if (typeof files === 'string') {
+    return new minplayer.file({'path': files});
+  }
+
+  // If the file is already a file object then just return.
+  if (files.path || files.id) {
+    return new minplayer.file(files);
+  }
+
+  // Add the files and get the best player to play.
+  var i = files.length, bestPriority = 0, mFile = null, file = null;
+  while (i--) {
+    file = files[i];
+
+    // Get the minplayer file object.
+    if (typeof file === 'string') {
+      file = new minplayer.file({'path': file});
+    }
+    else {
+      file = new minplayer.file(file);
+    }
+
+    // Determine the best file for this browser.
+    if (file.priority > bestPriority) {
+      mFile = file;
+    }
+  }
+
+  // Return the best minplayer file.
+  return mFile;
+};
+
+/**
+ * Loads a media player based on the current file.
+ */
+minplayer.prototype.loadPlayer = function() {
+
+  // Do nothing if there isn't a file.
+  if (!this.options.file) {
+    this.error('No media found.');
+    return;
+  }
+
+  if (!this.options.file.player) {
+    this.error('Cannot play media: ' + this.options.file.mimetype);
+    return;
+  }
+
+  // Reset the error.
+  this.error();
+
+  // Only destroy if the current player is different than the new player.
+  var player = this.options.file.player.toString();
+
+  // If there isn't media or if the players are different.
+  if (!this.media || (player !== this.currentPlayer)) {
+
+    // Set the current media player.
+    this.currentPlayer = player;
+
+    // Do nothing if we don't have a display.
+    if (!this.elements.display) {
+      this.error('No media display found.');
+      return;
+    }
+
+    // Destroy the current media.
+    var queue = {};
+    if (this.media) {
+      queue = this.media.queue;
+      this.media.destroy();
+    }
+
+    // Get the class name and create the new player.
+    pClass = minplayer.players[this.options.file.player];
+
+    // Create the new media player.
+    this.options.mediaelement = this.elements.media;
+    this.media = new pClass(this.elements.display, this.options, queue);
+
+    // Now get the media when it is ready.
+    this.get('media', (function(player) {
+      return function(media) {
+
+        // Load the media.
+        media.load(player.options.file);
+      };
+    })(this));
+  }
+  // If the media object already exists...
+  else if (this.media) {
+
+    // Now load the different media file.
+    this.media.load(this.options.file);
+  }
+};
+
+/**
+ * Load a set of files or a single file for the media player.
+ *
+ * @param {array} files An array of files to chose from to load.
+ */
+minplayer.prototype.load = function(files) {
+
+  // Set the id and class.
+  var id = '', pClass = '';
+
+  // If no file was provided, then get it.
+  this.options.files = files || this.options.files;
+  this.options.file = this.getMediaFile(this.options.files);
+
+  // Now load the player.
+  this.loadPlayer();
+};
+
+/**
+ * Called when the player is resized.
+ */
+minplayer.prototype.resize = function() {
+
+  // Call onRezie for each plugin.
+  this.get(function(plugin) {
+    plugin.onResize();
+  });
+};
diff --git a/core/modules/file/player/src/minplayer.playLoader.js b/core/modules/file/player/src/minplayer.playLoader.js
new file mode 100644
index 0000000000000000000000000000000000000000..ca8ba6013e12da61c774ef050c1df9fb7a207201
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.playLoader.js
@@ -0,0 +1,189 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The play loader base class, which is used to control the busy
+ * cursor, big play button, and the opaque background which shows when the
+ * player is paused.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ */
+minplayer.playLoader = function(context, options) {
+
+  // Define the flags that control the busy cursor.
+  this.busy = new minplayer.flags();
+
+  // Define the flags that control the big play button.
+  this.bigPlay = new minplayer.flags();
+
+  /** The preview image. */
+  this.preview = null;
+
+  // Derive from display
+  minplayer.display.call(this, 'playLoader', context, options);
+};
+
+/** Derive from minplayer.display. */
+minplayer.playLoader.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.playLoader.prototype.constructor = minplayer.playLoader;
+
+/**
+ * The constructor.
+ */
+minplayer.playLoader.prototype.construct = function() {
+
+  // Call the media display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Get the media plugin.
+  this.get('media', function(media) {
+
+    // Only bind if this player does not have its own play loader.
+    if (!media.hasPlayLoader()) {
+
+      // Get the poster image.
+      if (!this.options.preview) {
+        this.options.preview = media.elements.media.attr('poster');
+      }
+
+      // Reset the media's poster image.
+      media.elements.media.attr('poster', '');
+
+      // Load the preview image.
+      this.loadPreview();
+
+      // Trigger a play event when someone clicks on the controller.
+      if (this.elements.bigPlay) {
+        this.elements.bigPlay.unbind().bind('click', function(event) {
+          event.preventDefault();
+          jQuery(this).hide();
+          media.play();
+        });
+      }
+
+      // Bind to the player events to control the play loader.
+      media.unbind('loadstart').bind('loadstart', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', true);
+          playLoader.bigPlay.setFlag('media', true);
+          if (playLoader.preview) {
+            playLoader.elements.preview.show();
+          }
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('waiting', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', true);
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('loadeddata', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', false);
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('playing', (function(playLoader) {
+        return function(event) {
+          playLoader.busy.setFlag('media', false);
+          playLoader.bigPlay.setFlag('media', false);
+          if (playLoader.preview) {
+            playLoader.elements.preview.hide();
+          }
+          playLoader.checkVisibility();
+        };
+      })(this));
+      media.bind('pause', (function(playLoader) {
+        return function(event) {
+          playLoader.bigPlay.setFlag('media', true);
+          playLoader.checkVisibility();
+        };
+      })(this));
+    }
+    else {
+
+      // Hide the busy cursor.
+      if (this.elements.busy) {
+        this.elements.busy.unbind().hide();
+      }
+
+      // Hide the big play button.
+      if (this.elements.bigPlay) {
+        this.elements.bigPlay.unbind().hide();
+      }
+
+      // Hide the display.
+      this.display.unbind().hide();
+    }
+  });
+
+  // We are now ready.
+  this.ready();
+};
+
+/**
+ * Loads the preview image.
+ */
+minplayer.playLoader.prototype.loadPreview = function() {
+
+  // If the preview element exists.
+  if (this.elements.preview) {
+
+    // If there is a preview to show...
+    if (this.options.preview) {
+
+      // Say that this has a preview.
+      this.elements.preview.addClass('has-preview').show();
+
+      // Create a new preview image.
+      this.preview = new minplayer.image(this.elements.preview, this.options);
+
+      // Create the image.
+      this.preview.load(this.options.preview);
+    }
+    else {
+
+      // Hide the preview.
+      this.elements.preview.hide();
+    }
+  }
+};
+
+/**
+ * Hide or show certain elements based on the state of the busy and big play
+ * button.
+ */
+minplayer.playLoader.prototype.checkVisibility = function() {
+
+  // Hide or show the busy cursor based on the flags.
+  if (this.busy.flag) {
+    this.elements.busy.show();
+  }
+  else {
+    this.elements.busy.hide();
+  }
+
+  // Hide or show the big play button based on the flags.
+  if (this.bigPlay.flag) {
+    this.elements.bigPlay.show();
+  }
+  else {
+    this.elements.bigPlay.hide();
+  }
+
+  // Show the control either flag is set.
+  if (this.bigPlay.flag || this.busy.flag) {
+    this.display.show();
+  }
+
+  // Hide the whole control if both flags are 0.
+  if (!this.bigPlay.flag && !this.busy.flag) {
+    this.display.hide();
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.players.base.js b/core/modules/file/player/src/minplayer.players.base.js
new file mode 100644
index 0000000000000000000000000000000000000000..781f27b7045f4a762674aadd94fdd4daaafdb924
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.players.base.js
@@ -0,0 +1,591 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The base media player class where all media players derive from.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.base = function(context, options, queue) {
+
+  // Derive from display
+  minplayer.display.call(this, 'media', context, options, queue);
+};
+
+/** Derive from minplayer.display. */
+minplayer.players.base.prototype = new minplayer.display();
+
+/** Reset the constructor. */
+minplayer.players.base.prototype.constructor = minplayer.players.base;
+
+/**
+ * @see minplayer.display.getElements
+ * @this minplayer.players.base
+ * @return {object} The elements for this display.
+ */
+minplayer.players.base.prototype.getElements = function() {
+  var elements = minplayer.display.prototype.getElements.call(this);
+  return jQuery.extend(elements, {
+    media: this.options.mediaelement
+  });
+};
+
+/**
+ * Get the priority of this media player.
+ *
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.base.getPriority = function() {
+  return 0;
+};
+
+/**
+ * Returns the ID for the media being played.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {string} The ID for the provided media.
+ */
+minplayer.players.base.getMediaId = function(file) {
+  return '';
+};
+
+/**
+ * Determine if we can play the media file.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.base.canPlay = function(file) {
+  return false;
+};
+
+/**
+ * @see minplayer.plugin.construct
+ * @this minplayer.players.base
+ */
+minplayer.players.base.prototype.construct = function() {
+
+  // Call the media display constructor.
+  minplayer.display.prototype.construct.call(this);
+
+  // Clear the media player.
+  this.clear();
+
+  /** The currently loaded media file. */
+  this.mediaFile = this.options.file;
+
+  // Get the player display object.
+  if (!this.playerFound()) {
+
+    // Remove the media element if found
+    if (this.elements.media) {
+      this.elements.media.remove();
+    }
+
+    // Create a new media player element.
+    this.elements.media = jQuery(this.create());
+    this.display.html(this.elements.media);
+  }
+
+  // Get the player object...
+  this.player = this.getPlayer();
+
+  // Set the focus of the element based on if they click in or outside of it.
+  jQuery(document).bind('click', (function(player) {
+    return function(event) {
+      if (jQuery(event.target).closest('#' + player.options.id).length == 0) {
+        player.hasFocus = false;
+      }
+      else {
+        player.hasFocus = true;
+      }
+    };
+  })(this));
+
+  // Bind to key events...
+  jQuery(document).bind('keydown', (function(player) {
+    return function(event) {
+      if (player.hasFocus) {
+        event.preventDefault();
+        switch (event.keyCode) {
+          case 32:  // SPACE
+          case 179: // GOOGLE play/pause button.
+            if (player.playing) {
+              player.pause();
+            }
+            else {
+              player.play();
+            }
+            break;
+          case 38:  // UP
+            player.setVolumeRelative(0.1);
+            break;
+          case 40:  // DOWN
+            player.setVolumeRelative(-0.1);
+            break;
+          case 37:  // LEFT
+          case 227: // GOOGLE TV REW
+            player.seekRelative(-0.05);
+            break;
+          case 39:  // RIGHT
+          case 228: // GOOGLE TV FW
+            player.seekRelative(0.05);
+            break;
+        }
+      }
+    };
+  })(this));
+};
+
+/**
+ * @see minplayer.plugin.destroy.
+ */
+minplayer.players.base.prototype.destroy = function() {
+  minplayer.plugin.prototype.destroy.call(this);
+  this.clear();
+};
+
+/**
+ * Clears the media player.
+ */
+minplayer.players.base.prototype.clear = function() {
+
+  // Reset the ready flag.
+  this.playerReady = false;
+
+  // Reset the player.
+  this.reset();
+
+  // If the player exists, then unbind all events.
+  if (this.player) {
+    jQuery(this.player).unbind();
+  }
+};
+
+/**
+ * Resets all variables.
+ */
+minplayer.players.base.prototype.reset = function() {
+
+  // The duration of the player.
+  this.duration = new minplayer.async();
+
+  // The current play time of the player.
+  this.currentTime = new minplayer.async();
+
+  // The amount of bytes loaded in the player.
+  this.bytesLoaded = new minplayer.async();
+
+  // The total amount of bytes for the media.
+  this.bytesTotal = new minplayer.async();
+
+  // The bytes that the download started with.
+  this.bytesStart = new minplayer.async();
+
+  // The current volume of the player.
+  this.volume = new minplayer.async();
+
+  // Reset focus.
+  this.hasFocus = false;
+
+  // We are not playing.
+  this.playing = false;
+
+  // We are not loading.
+  this.loading = false;
+
+  // Tell everyone else we reset.
+  this.trigger('pause');
+  this.trigger('waiting');
+  this.trigger('progress', {loaded: 0, total: 0, start: 0});
+  this.trigger('timeupdate', {currentTime: 0, duration: 0});
+};
+
+/**
+ * Called when the player is ready to recieve events and commands.
+ */
+minplayer.players.base.prototype.onReady = function() {
+
+  // Only continue if we are not already ready.
+  if (this.playerReady) {
+    return;
+  }
+
+  // Set the ready flag.
+  this.playerReady = true;
+
+  // Set the volume to the default.
+  this.setVolume(this.options.volume / 100);
+
+  // Setup the progress interval.
+  this.loading = true;
+
+  // Create a poll to get the progress.
+  this.poll((function(player) {
+    return function() {
+
+      // Only do this if the play interval is set.
+      if (player.loading) {
+
+        // Get the bytes loaded asynchronously.
+        player.getBytesLoaded(function(bytesLoaded) {
+
+          // Get the bytes total asynchronously.
+          player.getBytesTotal(function(bytesTotal) {
+
+            // Trigger an event about the progress.
+            if (bytesLoaded || bytesTotal) {
+
+              // Get the bytes start, but don't require it.
+              var bytesStart = 0;
+              player.getBytesStart(function(val) {
+                bytesStart = val;
+              });
+
+              // Trigger a progress event.
+              player.trigger('progress', {
+                loaded: bytesLoaded,
+                total: bytesTotal,
+                start: bytesStart
+              });
+
+              // Say we are not longer loading if they are equal.
+              if (bytesLoaded >= bytesTotal) {
+                player.loading = false;
+              }
+            }
+          });
+        });
+      }
+
+      // Keep polling as long as its loading...
+      return player.loading;
+    };
+  })(this), 1000);
+
+  // We are now ready.
+  this.ready();
+
+  // Trigger that the load has started.
+  this.trigger('loadstart');
+};
+
+/**
+ * Should be called when the media is playing.
+ */
+minplayer.players.base.prototype.onPlaying = function() {
+
+  // Trigger an event that we are playing.
+  this.trigger('playing');
+
+  // Say that this player has focus.
+  this.hasFocus = true;
+
+  // Set the playInterval to true.
+  this.playing = true;
+
+  // Create a poll to get the timeupate.
+  this.poll((function(player) {
+    return function() {
+
+      // Only do this if the play interval is set.
+      if (player.playing) {
+
+        // Get the current time asyncrhonously.
+        player.getCurrentTime(function(currentTime) {
+
+          // Get the duration asynchronously.
+          player.getDuration(function(duration) {
+
+            // Convert these to floats.
+            currentTime = parseFloat(currentTime);
+            duration = parseFloat(duration);
+
+            // Trigger an event about the progress.
+            if (currentTime || duration) {
+
+              // Trigger an update event.
+              player.trigger('timeupdate', {
+                currentTime: currentTime,
+                duration: duration
+              });
+            }
+          });
+        });
+      }
+
+      // Keep polling as long as it is playing.
+      return player.playing;
+    };
+  })(this), 1000);
+};
+
+/**
+ * Should be called when the media is paused.
+ */
+minplayer.players.base.prototype.onPaused = function() {
+
+  // Trigger an event that we are paused.
+  this.trigger('pause');
+
+  // Remove focus.
+  this.hasFocus = false;
+
+  // Say we are not playing.
+  this.playing = false;
+};
+
+/**
+ * Should be called when the media is complete.
+ */
+minplayer.players.base.prototype.onComplete = function() {
+  // Stop the intervals.
+  this.playing = false;
+  this.loading = false;
+  this.hasFocus = false;
+  this.trigger('ended');
+};
+
+/**
+ * Should be called when the media is done loading.
+ */
+minplayer.players.base.prototype.onLoaded = function() {
+  this.trigger('loadeddata');
+};
+
+/**
+ * Should be called when the player is waiting.
+ */
+minplayer.players.base.prototype.onWaiting = function() {
+  this.trigger('waiting');
+};
+
+/**
+ * Called when an error occurs.
+ *
+ * @param {string} errorCode The error that was triggered.
+ */
+minplayer.players.base.prototype.onError = function(errorCode) {
+  this.hasFocus = false;
+  this.trigger('error', errorCode);
+};
+
+/**
+ * @see minplayer.players.base#isReady
+ * @return {boolean} Checks to see if the Flash is ready.
+ */
+minplayer.players.base.prototype.isReady = function() {
+
+  // Return that the player is set and the ready flag is good.
+  return (this.player && this.playerReady);
+};
+
+/**
+ * Determines if the player should show the playloader.
+ *
+ * @return {bool} If this player implements its own playLoader.
+ */
+minplayer.players.base.prototype.hasPlayLoader = function() {
+  return false;
+};
+
+/**
+ * Returns if the media player is already within the DOM.
+ *
+ * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
+ */
+minplayer.players.base.prototype.playerFound = function() {
+  return false;
+};
+
+/**
+ * Creates the media player and inserts it in the DOM.
+ *
+ * @return {object} The media player entity.
+ */
+minplayer.players.base.prototype.create = function() {
+  this.reset();
+  return null;
+};
+
+/**
+ * Returns the media player object.
+ *
+ * @return {object} The media player object.
+ */
+minplayer.players.base.prototype.getPlayer = function() {
+  return this.player;
+};
+
+/**
+ * Loads a new media player.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ */
+minplayer.players.base.prototype.load = function(file) {
+
+  // Store the media file for future lookup.
+  var isString = (typeof this.mediaFile == 'string');
+  var path = isString ? this.mediaFile : this.mediaFile.path;
+  if (file && (file.path != path)) {
+    this.reset();
+    this.mediaFile = file;
+  }
+};
+
+/**
+ * Play the loaded media file.
+ */
+minplayer.players.base.prototype.play = function() {
+};
+
+/**
+ * Pause the loaded media file.
+ */
+minplayer.players.base.prototype.pause = function() {
+};
+
+/**
+ * Stop the loaded media file.
+ */
+minplayer.players.base.prototype.stop = function() {
+  this.playing = false;
+  this.loading = false;
+  this.hasFocus = false;
+};
+
+/**
+ * Seeks to relative position.
+ *
+ * @param {number} pos Relative position.  -1 to 1 (percent), > 1 (seconds).
+ */
+minplayer.players.base.prototype.seekRelative = function(pos) {
+
+  // Get the current time asyncrhonously.
+  this.getCurrentTime((function(player) {
+    return function(currentTime) {
+
+      // Get the duration asynchronously.
+      player.getDuration(function(duration) {
+
+        // Only do this if we have a duration.
+        if (duration) {
+
+          // Get the position.
+          var seekPos = 0;
+          if ((pos > -1) && (pos < 1)) {
+            seekPos = (currentTime / duration) + parseFloat(pos);
+          }
+          else {
+            seekPos = (currentTime + parseFloat(pos)) / duration;
+          }
+
+          // Set the seek value.
+          player.seek(seekPos);
+        }
+      });
+    };
+  })(this));
+};
+
+/**
+ * Seek the loaded media.
+ *
+ * @param {number} pos The position to seek the minplayer. 0 to 1.
+ */
+minplayer.players.base.prototype.seek = function(pos) {
+};
+
+/**
+ * Set the volume of the loaded minplayer.
+ *
+ * @param {number} vol -1 to 1 - The relative amount to increase or decrease.
+ */
+minplayer.players.base.prototype.setVolumeRelative = function(vol) {
+
+  // Get the volume
+  this.getVolume((function(player) {
+    return function(newVol) {
+      newVol += parseFloat(vol);
+      newVol = (newVol < 0) ? 0 : newVol;
+      newVol = (newVol > 1) ? 1 : newVol;
+      player.setVolume(newVol);
+    };
+  })(this));
+};
+
+/**
+ * Set the volume of the loaded minplayer.
+ *
+ * @param {number} vol The volume to set the media. 0 to 1.
+ */
+minplayer.players.base.prototype.setVolume = function(vol) {
+  this.trigger('volumeupdate', vol);
+};
+
+/**
+ * Get the volume from the loaded media.
+ *
+ * @param {function} callback Called when the volume is determined.
+ * @return {number} The volume of the media; 0 to 1.
+ */
+minplayer.players.base.prototype.getVolume = function(callback) {
+  return this.volume.get(callback);
+};
+
+/**
+ * Get the current time for the media being played.
+ *
+ * @param {function} callback Called when the time is determined.
+ * @return {number} The volume of the media; 0 to 1.
+ */
+minplayer.players.base.prototype.getCurrentTime = function(callback) {
+  return this.currentTime.get(callback);
+};
+
+/**
+ * Return the duration of the loaded media.
+ *
+ * @param {function} callback Called when the duration is determined.
+ * @return {number} The duration of the loaded media.
+ */
+minplayer.players.base.prototype.getDuration = function(callback) {
+  return this.duration.get(callback);
+};
+
+/**
+ * Return the start bytes for the loaded media.
+ *
+ * @param {function} callback Called when the start bytes is determined.
+ * @return {int} The bytes that were started.
+ */
+minplayer.players.base.prototype.getBytesStart = function(callback) {
+  return this.bytesStart.get(callback);
+};
+
+/**
+ * Return the bytes of media loaded.
+ *
+ * @param {function} callback Called when the bytes loaded is determined.
+ * @return {int} The amount of bytes loaded.
+ */
+minplayer.players.base.prototype.getBytesLoaded = function(callback) {
+  return this.bytesLoaded.get(callback);
+};
+
+/**
+ * Return the total amount of bytes.
+ *
+ * @param {function} callback Called when the bytes total is determined.
+ * @return {int} The total amount of bytes for this media.
+ */
+minplayer.players.base.prototype.getBytesTotal = function(callback) {
+  return this.bytesTotal.get(callback);
+};
diff --git a/core/modules/file/player/src/minplayer.players.flash.js b/core/modules/file/player/src/minplayer.players.flash.js
new file mode 100644
index 0000000000000000000000000000000000000000..8afff596fcc160d9caf4f64cfad8d8b5cd502a20
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.players.flash.js
@@ -0,0 +1,108 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The Flash media player class to control the flash fallback.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.flash = function(context, options, queue) {
+
+  // Derive from players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.flash.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.flash.prototype.constructor = minplayer.players.flash;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.flash.getPriority = function() {
+  return 0;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.flash.canPlay = function(file) {
+  return false;
+};
+
+/**
+ * API to return the Flash player code provided params.
+ *
+ * @param {object} params The params used to populate the Flash code.
+ * @return {object} A Flash DOM element.
+ */
+minplayer.players.flash.getFlash = function(params) {
+  // Get the protocol.
+  var protocol = window.location.protocol;
+  if (protocol.charAt(protocol.length - 1) == ':') {
+    protocol = protocol.substring(0, protocol.length - 1);
+  }
+
+  // Convert the flashvars object to a string...
+  var flashVars = jQuery.param(params.flashvars);
+
+  // Set the codebase.
+  var codebase = protocol + '://fpdownload.macromedia.com';
+  codebase += '/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0';
+
+  // Get the HTML flash object string.
+  var flash = '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
+  flash += 'codebase="' + codebase + '" ';
+  flash += 'playerType="flash" ';
+  flash += 'width="' + params.width + '" ';
+  flash += 'height="' + params.height + '" ';
+  flash += 'id="' + params.id + '" ';
+  flash += 'name="' + params.id + '"> ';
+  flash += '<param name="allowScriptAccess" value="always"></param>';
+  flash += '<param name="allowfullscreen" value="true" />';
+  flash += '<param name="movie" value="' + params.swf + '"></param>';
+  flash += '<param name="wmode" value="' + params.wmode + '"></param>';
+  flash += '<param name="quality" value="high"></param>';
+  flash += '<param name="FlashVars" value="' + flashVars + '"></param>';
+  flash += '<embed src="' + params.swf + '" ';
+  flash += 'quality="high" ';
+  flash += 'width="' + params.width + '" height="' + params.height + '" ';
+  flash += 'id="' + params.id + '" name="' + params.id + '" ';
+  flash += 'swLiveConnect="true" allowScriptAccess="always" ';
+  flash += 'wmode="' + params.wmode + '"';
+  flash += 'allowfullscreen="true" type="application/x-shockwave-flash" ';
+  flash += 'FlashVars="' + flashVars + '" ';
+  flash += 'pluginspage="' + protocol;
+  flash += '://www.macromedia.com/go/getflashplayer" />';
+  flash += '</object>';
+  return flash;
+};
+
+/**
+ * @see minplayer.players.base#playerFound
+ * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
+ */
+minplayer.players.flash.prototype.playerFound = function() {
+  return (this.display.find('object[playerType="flash"]').length > 0);
+};
+
+/**
+ * @see minplayer.players.base#getPlayer
+ * @return {object} The media player object.
+ */
+minplayer.players.flash.prototype.getPlayer = function() {
+  // IE needs the object, everyone else just needs embed.
+  var object = jQuery.browser.msie ? 'object' : 'embed';
+  return jQuery(object, this.display).eq(0)[0];
+};
diff --git a/core/modules/file/player/src/minplayer.players.html5.js b/core/modules/file/player/src/minplayer.players.html5.js
new file mode 100644
index 0000000000000000000000000000000000000000..34704130ec61d5b28a9493a67e1837efd096385e
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.players.html5.js
@@ -0,0 +1,343 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The HTML5 media player implementation.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.html5 = function(context, options, queue) {
+
+  // Derive players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.html5.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.html5.prototype.constructor = minplayer.players.html5;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.html5.getPriority = function() {
+  return 10;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.html5.canPlay = function(file) {
+  switch (file.mimetype) {
+    case 'video/ogg':
+      return !!minplayer.playTypes.videoOGG;
+    case 'video/mp4':
+    case 'video/x-mp4':
+    case 'video/m4v':
+    case 'video/x-m4v':
+      return !!minplayer.playTypes.videoH264;
+    case 'video/x-webm':
+    case 'video/webm':
+    case 'application/octet-stream':
+      return !!minplayer.playTypes.videoWEBM;
+    case 'audio/ogg':
+      return !!minplayer.playTypes.audioOGG;
+    case 'audio/mpeg':
+      return !!minplayer.playTypes.audioMP3;
+    case 'audio/mp4':
+      return !!minplayer.playTypes.audioMP4;
+    default:
+      return false;
+  }
+};
+
+/**
+ * @see minplayer.plugin.construct
+ */
+minplayer.players.html5.prototype.construct = function() {
+
+  // Call base constructor.
+  minplayer.players.base.prototype.construct.call(this);
+
+  // For the HTML5 player, we will just pass events along...
+  if (this.player) {
+
+    this.player.addEventListener('abort', (function(player) {
+      return function() {
+        player.trigger('abort');
+      };
+    })(this), false);
+    this.player.addEventListener('loadstart', (function(player) {
+      return function() {
+        player.onReady();
+      };
+    })(this), false);
+    this.player.addEventListener('loadeddata', (function(player) {
+      return function() {
+        player.onLoaded();
+      };
+    })(this), false);
+    this.player.addEventListener('loadedmetadata', (function(player) {
+      return function() {
+        player.onLoaded();
+      };
+    })(this), false);
+    this.player.addEventListener('canplaythrough', (function(player) {
+      return function() {
+        player.onLoaded();
+      };
+    })(this), false);
+    this.player.addEventListener('ended', (function(player) {
+      return function() {
+        player.onComplete();
+      };
+    })(this), false);
+    this.player.addEventListener('pause', (function(player) {
+      return function() {
+        player.onPaused();
+      };
+    })(this), false);
+    this.player.addEventListener('play', (function(player) {
+      return function() {
+        player.onPlaying();
+      };
+    })(this), false);
+    this.player.addEventListener('playing', (function(player) {
+      return function() {
+        player.onPlaying();
+      };
+    })(this), false);
+    this.player.addEventListener('error', (function(player) {
+      return function() {
+        player.trigger('error', 'An error occured - ' + this.error.code);
+      };
+    })(this), false);
+    this.player.addEventListener('waiting', (function(player) {
+      return function() {
+        player.onWaiting();
+      };
+    })(this), false);
+    this.player.addEventListener('durationchange', (function(player) {
+      return function() {
+        player.duration.set(this.duration);
+        player.trigger('durationchange', {duration: this.duration});
+      };
+    })(this), false);
+    this.player.addEventListener('progress', (function(player) {
+      return function(event) {
+        player.bytesTotal.set(event.total);
+        player.bytesLoaded.set(event.loaded);
+      };
+    })(this), false);
+
+    // Say we are ready.
+    this.onReady();
+  }
+};
+
+/**
+ * @see minplayer.players.base#playerFound
+ * @return {boolean} TRUE - if the player is in the DOM, FALSE otherwise.
+ */
+minplayer.players.html5.prototype.playerFound = function() {
+  return (this.display.find(this.mediaFile.type).length > 0);
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.html5.prototype.create = function() {
+  minplayer.players.base.prototype.create.call(this);
+  var element = jQuery(document.createElement(this.mediaFile.type))
+  .attr(this.options.attributes)
+  .append(
+    jQuery(document.createElement('source')).attr({
+      'src': this.mediaFile.path
+    })
+  );
+
+  // Fix the fluid width and height.
+  element.eq(0)[0].setAttribute('width', '100%');
+  element.eq(0)[0].setAttribute('height', '100%');
+  return element;
+};
+
+/**
+ * @see minplayer.players.base#getPlayer
+ * @return {object} The media player object.
+ */
+minplayer.players.html5.prototype.getPlayer = function() {
+  return this.elements.media.eq(0)[0];
+};
+
+/**
+ * @see minplayer.players.base#load
+ */
+minplayer.players.html5.prototype.load = function(file) {
+
+  if (file) {
+
+    // Get the current source.
+    var src = this.elements.media.attr('src');
+    if (!src) {
+      src = jQuery('source', this.elements.media).eq(0).attr('src');
+    }
+
+    // If the source is different.
+    if (src != file.path) {
+
+      // Change the source...
+      var code = '<source src="' + file.path + '">';
+      this.elements.media.removeAttr('src').empty().html(code);
+    }
+  }
+
+  // Always call the base first on load...
+  minplayer.players.base.prototype.load.call(this, file);
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.html5.prototype.play = function() {
+  minplayer.players.base.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.play();
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.html5.prototype.pause = function() {
+  minplayer.players.base.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.pause();
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.html5.prototype.stop = function() {
+  minplayer.players.base.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.pause();
+    this.player.src = '';
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.html5.prototype.seek = function(pos) {
+  minplayer.players.base.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.currentTime = pos;
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.html5.prototype.setVolume = function(vol) {
+  minplayer.players.base.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.player.volume = vol;
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.html5.prototype.getVolume = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.volume);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getDuration
+ */
+minplayer.players.html5.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.duration);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getCurrentTime
+ */
+minplayer.players.html5.prototype.getCurrentTime = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.currentTime);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesLoaded
+ */
+minplayer.players.html5.prototype.getBytesLoaded = function(callback) {
+  if (this.isReady()) {
+    var loaded = 0;
+
+    // Check several different possibilities.
+    if (this.bytesLoaded.value) {
+      loaded = this.bytesLoaded.value;
+    }
+    else if (this.player.buffered &&
+        this.player.buffered.length > 0 &&
+        this.player.buffered.end &&
+        this.player.duration) {
+      loaded = this.player.buffered.end(0);
+    }
+    else if (this.player.bytesTotal != undefined &&
+             this.player.bytesTotal > 0 &&
+             this.player.bufferedBytes != undefined) {
+      loaded = this.player.bufferedBytes;
+    }
+
+    // Return the loaded amount.
+    callback(loaded);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesTotal
+ */
+minplayer.players.html5.prototype.getBytesTotal = function(callback) {
+  if (this.isReady()) {
+
+    var total = 0;
+
+    // Check several different possibilities.
+    if (this.bytesTotal.value) {
+      total = this.bytesTotal.value;
+    }
+    else if (this.player.buffered &&
+        this.player.buffered.length > 0 &&
+        this.player.buffered.end &&
+        this.player.duration) {
+      total = this.player.duration;
+    }
+    else if (this.player.bytesTotal != undefined &&
+             this.player.bytesTotal > 0 &&
+             this.player.bufferedBytes != undefined) {
+      total = this.player.bytesTotal;
+    }
+
+    // Return the loaded amount.
+    callback(total);
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.players.minplayer.js b/core/modules/file/player/src/minplayer.players.minplayer.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad224e2fc7ac0d075653af30e4e8c939c93ec771
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.players.minplayer.js
@@ -0,0 +1,275 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.display
+ * @class The Flash media player class to control the flash fallback.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.minplayer = function(context, options, queue) {
+
+  // Derive from players flash.
+  minplayer.players.flash.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.flash. */
+minplayer.players.minplayer.prototype = new minplayer.players.flash();
+
+/** Reset the constructor. */
+minplayer.players.minplayer.prototype.constructor = minplayer.players.minplayer;
+
+/**
+ * Called when the Flash player is ready.
+ *
+ * @param {string} id The media player ID.
+ */
+window.onFlashPlayerReady = function(id) {
+  var media = minplayer.get(id, 'media');
+  if (media) {
+    media.onReady();
+  }
+};
+
+/**
+ * Called when the Flash player updates.
+ *
+ * @param {string} id The media player ID.
+ * @param {string} eventType The event type that was triggered.
+ */
+window.onFlashPlayerUpdate = function(id, eventType) {
+  var media = minplayer.get(id, 'media');
+  if (media) {
+    media.onMediaUpdate(eventType);
+  }
+};
+
+/**
+ * Used to debug from the Flash player to the browser console.
+ *
+ * @param {string} debug The debug string.
+ */
+window.onFlashPlayerDebug = function(debug) {
+  minplayer.console.log(debug);
+};
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.minplayer.getPriority = function() {
+  return 1;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.minplayer.canPlay = function(file) {
+  switch (file.mimetype) {
+    case 'video/mp4':
+    case 'video/x-mp4':
+    case 'video/m4v':
+    case 'video/x-m4v':
+    case 'video/x-webm':
+    case 'video/webm':
+    case 'application/octet-stream':
+    case 'video/quicktime':
+    case 'video/3gpp2':
+    case 'video/3gpp':
+    case 'application/x-shockwave-flash':
+    case 'audio/mpeg':
+    case 'audio/mp4':
+    case 'audio/aac':
+    case 'audio/vnd.wave':
+    case 'audio/x-ms-wma':
+      return true;
+
+    default:
+      return false;
+  }
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.minplayer.prototype.create = function() {
+
+  // Make sure we provide default options...
+  this.options = jQuery.extend({
+    swfplayer: 'flash/minplayer.swf'
+  }, this.options);
+
+  minplayer.players.flash.prototype.create.call(this);
+
+  // The flash variables for this flash player.
+  var flashVars = {
+    'id': this.options.id,
+    'debug': this.options.debug,
+    'config': 'nocontrols',
+    'file': this.mediaFile.path,
+    'autostart': this.options.autoplay
+  };
+
+  // Return a flash media player object.
+  return minplayer.players.flash.getFlash({
+    swf: this.options.swfplayer,
+    id: this.options.id + '_player',
+    width: this.options.width,
+    height: '100%',
+    flashvars: flashVars,
+    wmode: this.options.wmode
+  });
+};
+
+/**
+ * Called when the Flash player has an update.
+ *
+ * @param {string} eventType The event that was triggered in the player.
+ */
+minplayer.players.minplayer.prototype.onMediaUpdate = function(eventType) {
+  switch (eventType) {
+    case 'mediaMeta':
+      this.onLoaded();
+      break;
+    case 'mediaPlaying':
+      this.onPlaying();
+      break;
+    case 'mediaPaused':
+      this.onPaused();
+      break;
+    case 'mediaComplete':
+      this.onComplete();
+      break;
+  }
+};
+
+/**
+ * @see minplayer.players.base#load
+ */
+minplayer.players.minplayer.prototype.load = function(file) {
+  minplayer.players.flash.prototype.load.call(this, file);
+  if (file && this.isReady()) {
+    this.player.loadMedia(file.path, file.stream);
+  }
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.minplayer.prototype.play = function() {
+  minplayer.players.flash.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.playMedia();
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.minplayer.prototype.pause = function() {
+  minplayer.players.flash.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.pauseMedia();
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.minplayer.prototype.stop = function() {
+  minplayer.players.flash.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.stopMedia();
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.minplayer.prototype.seek = function(pos) {
+  minplayer.players.flash.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.seekMedia(pos);
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.minplayer.prototype.setVolume = function(vol) {
+  minplayer.players.flash.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.player.setVolume(vol);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.minplayer.prototype.getVolume = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVolume());
+  }
+};
+
+/**
+ * @see minplayer.players.flash#getDuration
+ */
+minplayer.players.minplayer.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+
+    // Check to see if it is immediately available.
+    var duration = this.player.getDuration();
+    if (duration) {
+      callback(duration);
+    }
+    else {
+
+      // If not, then poll every second for the duration.
+      this.poll((function(player) {
+        return function() {
+          duration = player.player.getDuration();
+          if (duration) {
+            callback(duration);
+          }
+          return !duration;
+        };
+      })(this), 1000);
+    }
+  }
+};
+
+/**
+ * @see minplayer.players.base#getCurrentTime
+ */
+minplayer.players.minplayer.prototype.getCurrentTime = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getCurrentTime());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesLoaded
+ */
+minplayer.players.minplayer.prototype.getBytesLoaded = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getMediaBytesLoaded());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesTotal.
+ */
+minplayer.players.minplayer.prototype.getBytesTotal = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getMediaBytesTotal());
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.players.vimeo.js b/core/modules/file/player/src/minplayer.players.vimeo.js
new file mode 100644
index 0000000000000000000000000000000000000000..a7a9b88a8e05f16c8ad28aff10fdf4637576b508
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.players.vimeo.js
@@ -0,0 +1,262 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.players.base
+ * @class The vimeo media player.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.vimeo = function(context, options, queue) {
+
+  // Derive from players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.vimeo.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.vimeo.prototype.constructor = minplayer.players.vimeo;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.vimeo.getPriority = function() {
+  return 10;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.vimeo.canPlay = function(file) {
+
+  // Check for the mimetype for vimeo.
+  if (file.mimetype === 'video/vimeo') {
+    return true;
+  }
+
+  // If the path is a vimeo path, then return true.
+  return (file.path.search(/^http(s)?\:\/\/(www\.)?vimeo\.com/i) === 0);
+};
+
+/**
+ * Return the ID for a provided media file.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {string} The ID for the provided media.
+ */
+minplayer.players.vimeo.getMediaId = function(file) {
+  var regex = /^http[s]?\:\/\/(www\.)?vimeo\.com\/(\?v\=)?([0-9]+)/i;
+  if (file.path.search(regex) === 0) {
+    return file.path.match(regex)[3];
+  }
+  else {
+    return file.path;
+  }
+};
+
+/**
+ * @see minplayer.players.base#reset
+ */
+minplayer.players.vimeo.prototype.reset = function() {
+
+  // Reset the flash variables..
+  minplayer.players.base.prototype.reset.call(this);
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.vimeo.prototype.create = function() {
+  minplayer.players.base.prototype.create.call(this);
+
+  // Insert the Vimeo Froogaloop player.
+  var tag = document.createElement('script');
+  tag.src = 'http://a.vimeocdn.com/js/froogaloop2.min.js';
+  var firstScriptTag = document.getElementsByTagName('script')[0];
+  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+
+  // Create the iframe for this player.
+  var iframe = document.createElement('iframe');
+  iframe.setAttribute('id', this.options.id + '-player');
+  iframe.setAttribute('type', 'text/html');
+  iframe.setAttribute('width', '100%');
+  iframe.setAttribute('height', '100%');
+  iframe.setAttribute('frameborder', '0');
+
+  // Get the source.
+  var src = 'http://player.vimeo.com/video/';
+  src += this.mediaFile.id + '?';
+
+  // Add the parameters to the src.
+  src += jQuery.param({
+    'wmode': 'opaque',
+    'api': 1,
+    'player_id': this.options.id + '-player',
+    'title': 0,
+    'byline': 0,
+    'portrait': 0,
+    'autoplay': this.options.autoplay,
+    'loop': this.options.loop
+  });
+
+  // Set the source of the iframe.
+  iframe.setAttribute('src', src);
+
+  // Now register this player when the froogaloop code is loaded.
+  this.poll((function(player) {
+    return function() {
+      if (window.Froogaloop) {
+        player.player = window.Froogaloop(iframe);
+        player.player.addEvent('ready', function() {
+          player.onReady();
+        });
+      }
+      return !window.Froogaloop;
+    };
+  })(this), 200);
+
+  // Trigger that the load has started.
+  this.trigger('loadstart');
+
+  // Return the player.
+  return iframe;
+};
+
+/**
+ * @see minplayer.players.base#onReady
+ */
+minplayer.players.vimeo.prototype.onReady = function(player_id) {
+
+  // Add the other listeners.
+  this.player.addEvent('loadProgress', (function(player) {
+    return function(progress) {
+      player.duration.set(parseFloat(progress.duration));
+      player.bytesLoaded.set(progress.bytesLoaded);
+      player.bytesTotal.set(progress.bytesTotal);
+    };
+  })(this));
+
+  this.player.addEvent('playProgress', (function(player) {
+    return function(progress) {
+      player.duration.set(parseFloat(progress.duration));
+      player.currentTime.set(parseFloat(progress.seconds));
+    };
+  })(this));
+
+  this.player.addEvent('play', (function(player) {
+    return function() {
+      player.onPlaying();
+    };
+  })(this));
+
+  this.player.addEvent('pause', (function(player) {
+    return function() {
+      player.onPaused();
+    };
+  })(this));
+
+  this.player.addEvent('finish', (function(player) {
+    return function() {
+      player.onComplete();
+    };
+  })(this));
+
+  minplayer.players.base.prototype.onReady.call(this);
+  this.onLoaded();
+};
+
+/**
+ * Checks to see if this player can be found.
+ * @return {bool} TRUE - Player is found, FALSE - otherwise.
+ */
+minplayer.players.vimeo.prototype.playerFound = function() {
+  var iframe = this.display.find('iframe#' + this.options.id + '-player');
+  return (iframe.length > 0);
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.vimeo.prototype.play = function() {
+  minplayer.players.base.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.api('play');
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.vimeo.prototype.pause = function() {
+  minplayer.players.base.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.api('pause');
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.vimeo.prototype.stop = function() {
+  minplayer.players.base.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.api('unload');
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.vimeo.prototype.seek = function(pos) {
+  minplayer.players.base.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.api('seekTo', pos);
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.vimeo.prototype.setVolume = function(vol) {
+  minplayer.players.base.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.volume.set(vol);
+    this.player.api('setVolume', vol);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.vimeo.prototype.getVolume = function(callback) {
+  this.player.api('getVolume', function(vol) {
+    callback(vol);
+  });
+};
+
+/**
+ * @see minplayer.players.base#getDuration.
+ */
+minplayer.players.vimeo.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+    if (this.duration.value) {
+      callback(this.duration.value);
+    }
+    else {
+      this.player.api('getDuration', function(duration) {
+        callback(duration);
+      });
+    }
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.players.youtube.js b/core/modules/file/player/src/minplayer.players.youtube.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed724197092b5aca62dd588d56489a1b1838779a
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.players.youtube.js
@@ -0,0 +1,346 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+/** All the media player implementations */
+minplayer.players = minplayer.players || {};
+
+/**
+ * @constructor
+ * @extends minplayer.players.base
+ * @class The YouTube media player.
+ *
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.players.youtube = function(context, options, queue) {
+
+  /** The quality of the YouTube stream. */
+  this.quality = 'default';
+
+  // Derive from players base.
+  minplayer.players.base.call(this, context, options, queue);
+};
+
+/** Derive from minplayer.players.base. */
+minplayer.players.youtube.prototype = new minplayer.players.base();
+
+/** Reset the constructor. */
+minplayer.players.youtube.prototype.constructor = minplayer.players.youtube;
+
+/**
+ * @see minplayer.players.base#getPriority
+ * @return {number} The priority of this media player.
+ */
+minplayer.players.youtube.getPriority = function() {
+  return 10;
+};
+
+/**
+ * @see minplayer.players.base#canPlay
+ * @return {boolean} If this player can play this media type.
+ */
+minplayer.players.youtube.canPlay = function(file) {
+
+  // Check for the mimetype for youtube.
+  if (file.mimetype === 'video/youtube') {
+    return true;
+  }
+
+  // If the path is a YouTube path, then return true.
+  return (file.path.search(/^http(s)?\:\/\/(www\.)?youtube\.com/i) === 0);
+};
+
+/**
+ * Return the ID for a provided media file.
+ *
+ * @param {object} file A {@link minplayer.file} object.
+ * @return {string} The ID for the provided media.
+ */
+minplayer.players.youtube.getMediaId = function(file) {
+  var regex = /^http[s]?\:\/\/(www\.)?youtube\.com\/watch\?v=([a-zA-Z0-9]+)/i;
+  if (file.path.search(regex) === 0) {
+    return file.path.match(regex)[2];
+  }
+  else {
+    return file.path;
+  }
+};
+
+/**
+ * Register this youtube player so that multiple players can be present
+ * on the same page without event collision.
+ */
+minplayer.players.youtube.prototype.register = function() {
+
+  /**
+   * Register the standard youtube api ready callback.
+   */
+  window.onYouTubePlayerAPIReady = function() {
+
+    // Iterate over each media player.
+    jQuery.each(minplayer.get(null, 'player'), function(id, player) {
+
+      // Make sure this is the youtube player.
+      if (player.currentPlayer == 'youtube') {
+
+        // Create a new youtube player object for this instance only.
+        var playerId = id + '-player';
+
+        // Set this players media.
+        player.media.player = new YT.Player(playerId, {
+          events: {
+            'onReady': function(event) {
+              player.media.onReady(event);
+            },
+            'onStateChange': function(event) {
+              player.media.onPlayerStateChange(event);
+            },
+            'onPlaybackQualityChange': function(newQuality) {
+              player.media.onQualityChange(newQuality);
+            },
+            'onError': function(errorCode) {
+              player.media.onError(errorCode);
+            }
+          }
+        });
+      }
+    });
+  }
+};
+
+/**
+ * Translates the player state for the YouTube API player.
+ *
+ * @param {number} playerState The YouTube player state.
+ */
+minplayer.players.youtube.prototype.setPlayerState = function(playerState) {
+  switch (playerState) {
+    case YT.PlayerState.CUED:
+      break;
+    case YT.PlayerState.BUFFERING:
+      this.onWaiting();
+      break;
+    case YT.PlayerState.PAUSED:
+      this.onPaused();
+      break;
+    case YT.PlayerState.PLAYING:
+      this.onPlaying();
+      break;
+    case YT.PlayerState.ENDED:
+      this.onComplete();
+      break;
+    default:
+      break;
+  }
+};
+
+/**
+ * Called when an error occurs.
+ *
+ * @param {string} event The onReady event that was triggered.
+ */
+minplayer.players.youtube.prototype.onReady = function(event) {
+  minplayer.players.base.prototype.onReady.call(this);
+  this.onLoaded();
+};
+
+/**
+ * Checks to see if this player can be found.
+ * @return {bool} TRUE - Player is found, FALSE - otherwise.
+ */
+minplayer.players.youtube.prototype.playerFound = function() {
+  var iframe = this.display.find('iframe#' + this.options.id + '-player');
+  return (iframe.length > 0);
+};
+
+/**
+ * Called when the player state changes.
+ *
+ * @param {object} event A JavaScript Event.
+ */
+minplayer.players.youtube.prototype.onPlayerStateChange = function(event) {
+  this.setPlayerState(event.data);
+};
+
+/**
+ * Called when the player quality changes.
+ *
+ * @param {string} newQuality The new quality for the change.
+ */
+minplayer.players.youtube.prototype.onQualityChange = function(newQuality) {
+  this.quality = newQuality.data;
+};
+
+/**
+ * Determines if the player should show the playloader.
+ *
+ * @return {bool} If this player implements its own playLoader.
+ */
+minplayer.players.youtube.prototype.hasPlayLoader = function() {
+  return true;
+};
+
+/**
+ * @see minplayer.players.base#create
+ * @return {object} The media player entity.
+ */
+minplayer.players.youtube.prototype.create = function() {
+  minplayer.players.base.prototype.create.call(this);
+
+  // Insert the YouTube iframe API player.
+  var tag = document.createElement('script');
+  tag.src = 'http://www.youtube.com/player_api?enablejsapi=1';
+  var firstScriptTag = document.getElementsByTagName('script')[0];
+  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
+
+  // Now register this player.
+  this.register();
+
+  // Create the iframe for this player.
+  var iframe = document.createElement('iframe');
+  iframe.setAttribute('id', this.options.id + '-player');
+  iframe.setAttribute('type', 'text/html');
+  iframe.setAttribute('width', '100%');
+  iframe.setAttribute('height', '100%');
+  iframe.setAttribute('frameborder', '0');
+
+  // Get the source.
+  var src = 'http://www.youtube.com/embed/';
+  src += this.mediaFile.id + '?';
+
+  // Determine the origin of this script.
+  var origin = location.protocol;
+  origin += '//' + location.hostname;
+  origin += (location.port && ':' + location.port);
+
+  // Add the parameters to the src.
+  src += jQuery.param({
+    'wmode': 'opaque',
+    'controls': 0,
+    'enablejsapi': 1,
+    'origin': origin,
+    'autoplay': this.options.autoplay,
+    'loop': this.options.loop
+  });
+
+  // Set the source of the iframe.
+  iframe.setAttribute('src', src);
+
+  // Return the player.
+  return iframe;
+};
+
+/**
+ * @see minplayer.players.base#load
+ */
+minplayer.players.youtube.prototype.load = function(file) {
+  minplayer.players.base.prototype.load.call(this, file);
+  if (file && this.isReady()) {
+    this.player.loadVideoById(file.id, 0, this.quality);
+  }
+};
+
+/**
+ * @see minplayer.players.base#play
+ */
+minplayer.players.youtube.prototype.play = function() {
+  minplayer.players.base.prototype.play.call(this);
+  if (this.isReady()) {
+    this.player.playVideo();
+  }
+};
+
+/**
+ * @see minplayer.players.base#pause
+ */
+minplayer.players.youtube.prototype.pause = function() {
+  minplayer.players.base.prototype.pause.call(this);
+  if (this.isReady()) {
+    this.player.pauseVideo();
+  }
+};
+
+/**
+ * @see minplayer.players.base#stop
+ */
+minplayer.players.youtube.prototype.stop = function() {
+  minplayer.players.base.prototype.stop.call(this);
+  if (this.isReady()) {
+    this.player.stopVideo();
+  }
+};
+
+/**
+ * @see minplayer.players.base#seek
+ */
+minplayer.players.youtube.prototype.seek = function(pos) {
+  minplayer.players.base.prototype.seek.call(this, pos);
+  if (this.isReady()) {
+    this.player.seekTo(pos, true);
+  }
+};
+
+/**
+ * @see minplayer.players.base#setVolume
+ */
+minplayer.players.youtube.prototype.setVolume = function(vol) {
+  minplayer.players.base.prototype.setVolume.call(this, vol);
+  if (this.isReady()) {
+    this.player.setVolume(vol * 100);
+  }
+};
+
+/**
+ * @see minplayer.players.base#getVolume
+ */
+minplayer.players.youtube.prototype.getVolume = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVolume());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getDuration.
+ */
+minplayer.players.youtube.prototype.getDuration = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getDuration());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getCurrentTime
+ */
+minplayer.players.youtube.prototype.getCurrentTime = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getCurrentTime());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesStart.
+ */
+minplayer.players.youtube.prototype.getBytesStart = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVideoStartBytes());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesLoaded.
+ */
+minplayer.players.youtube.prototype.getBytesLoaded = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVideoBytesLoaded());
+  }
+};
+
+/**
+ * @see minplayer.players.base#getBytesTotal.
+ */
+minplayer.players.youtube.prototype.getBytesTotal = function(callback) {
+  if (this.isReady()) {
+    callback(this.player.getVideoBytesTotal());
+  }
+};
diff --git a/core/modules/file/player/src/minplayer.plugin.js b/core/modules/file/player/src/minplayer.plugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..321f54b1934a2ecd829708ec61cac34f6938952d
--- /dev/null
+++ b/core/modules/file/player/src/minplayer.plugin.js
@@ -0,0 +1,549 @@
+/** The minplayer namespace. */
+minplayer = minplayer || {};
+
+/** Static array to keep track of all plugins. */
+minplayer.plugins = minplayer.plugins || {};
+
+/** Static array to keep track of queues. */
+minplayer.queue = minplayer.queue || [];
+
+/** Mutex lock to keep multiple triggers from occuring. */
+minplayer.lock = false;
+
+/**
+ * @constructor
+ * @class The base class for all plugins.
+ *
+ * @param {string} name The name of this plugin.
+ * @param {object} context The jQuery context.
+ * @param {object} options This components options.
+ * @param {object} queue The event queue to pass events around.
+ */
+minplayer.plugin = function(name, context, options, queue) {
+
+  /** The name of this plugin. */
+  this.name = name;
+
+  /** The ready flag. */
+  this.pluginReady = false;
+
+  /** The options for this plugin. */
+  this.options = options || {};
+
+  /** The event queue. */
+  this.queue = queue || {};
+
+  /** Keep track of already triggered events. */
+  this.triggered = {};
+
+  /** Create a queue lock. */
+  this.lock = false;
+
+  // Only call the constructor if we have a context.
+  if (context) {
+
+    /** Keep track of the context. */
+    this.context = context;
+
+    // Construct this plugin.
+    this.construct();
+  }
+};
+
+/**
+ * The constructor which is called once the context is set.
+ * Any class deriving from the plugin class should place all context
+ * dependant functionality within this function instead of the standard
+ * constructor function since it is called on object derivation as well
+ * as object creation.
+ */
+minplayer.plugin.prototype.construct = function() {
+
+  // Adds this as a plugin.
+  this.addPlugin();
+};
+
+/**
+ * Destructor.
+ */
+minplayer.plugin.prototype.destroy = function() {
+
+  // Unbind all events.
+  this.unbind();
+};
+
+/**
+ * Creates a new plugin within this context.
+ *
+ * @param {string} name The name of the plugin you wish to create.
+ * @param {object} base The base object for this plugin.
+ * @param {object} context The context which you would like to create.
+ * @return {object} The new plugin object.
+ */
+minplayer.plugin.prototype.create = function(name, base, context) {
+  var plugin = null;
+
+  // Make sure we have a base object.
+  base = base || 'minplayer';
+
+  // Make sure there is a context.
+  context = context || this.display;
+
+  // See if this plugin exists within this object.
+  if (window[base][name]) {
+
+    // Set the plugin.
+    plugin = window[base][name];
+
+    // See if a template version of the plugin exists.
+    if (plugin[this.options.template]) {
+
+      plugin = plugin[this.options.template];
+    }
+
+    // Create the new plugin.
+    return new plugin(context, this.options);
+  }
+
+  return null;
+};
+
+/**
+ * Plugins should call this method when they are ready.
+ */
+minplayer.plugin.prototype.ready = function() {
+
+  // Keep this plugin from triggering multiple ready events.
+  if (!this.pluginReady) {
+
+    // Set the ready flag.
+    this.pluginReady = true;
+
+    // Now trigger that I am ready.
+    this.trigger('ready');
+
+    // Check the queue.
+    this.checkQueue();
+  }
+};
+
+/**
+ * Adds a new plugin to this player.
+ *
+ * @param {string} name The name of this plugin.
+ * @param {object} plugin A new plugin object, derived from media.plugin.
+ */
+minplayer.plugin.prototype.addPlugin = function(name, plugin) {
+  name = name || this.name;
+  plugin = plugin || this;
+
+  // Make sure the plugin is valid.
+  if (plugin.isValid()) {
+
+    // If the plugins for this instance do not exist.
+    if (!minplayer.plugins[this.options.id]) {
+
+      // Initialize the plugins.
+      minplayer.plugins[this.options.id] = {};
+    }
+
+    // Add this plugin.
+    minplayer.plugins[this.options.id][name] = plugin;
+  }
+};
+
+/**
+ * Create a polling timer.
+ *
+ * @param {function} callback The function to call when you poll.
+ * @param {integer} interval The interval you would like to poll.
+ */
+minplayer.plugin.prototype.poll = function(callback, interval) {
+  setTimeout((function(context) {
+    return function callLater() {
+      if (callback.call(context)) {
+        setTimeout(callLater, interval);
+      }
+    };
+  })(this), interval);
+};
+
+/**
+ * Gets a plugin by name and calls callback when it is ready.
+ *
+ * @param {string} plugin The plugin of the plugin.
+ * @param {function} callback Called when the plugin is ready.
+ * @return {object} The plugin if no callback is provided.
+ */
+minplayer.plugin.prototype.get = function(plugin, callback) {
+
+  // If they pass just a callback, then return all plugins when ready.
+  if (typeof plugin === 'function') {
+    callback = plugin;
+    plugin = null;
+  }
+
+  // Return the minplayer.get equivalent.
+  return minplayer.get.call(this, this.options.id, plugin, callback);
+};
+
+/**
+ * Check the queue and execute it.
+ */
+minplayer.plugin.prototype.checkQueue = function() {
+
+  // Initialize our variables.
+  var q = null, i = 0, check = false, newqueue = [];
+
+  // Set the lock.
+  minplayer.lock = true;
+
+  // Iterate through all the queues.
+  var length = minplayer.queue.length;
+  for (i = 0; i < length; i++) {
+
+    // Get the queue.
+    q = minplayer.queue[i];
+
+    // Now check to see if this queue is about us.
+    check = !q.id && !q.plugin;
+    check |= (q.plugin == this.name) && (!q.id || (q.id == this.options.id));
+
+    // If the check passes...
+    if (check) {
+      check = minplayer.bind.call(
+        q.context,
+        q.event,
+        this.options.id,
+        this.name,
+        q.callback
+      );
+    }
+
+    // Add the queue back if it doesn't check out.
+    if (!check) {
+
+      // Add this back to the queue.
+      newqueue.push(q);
+    }
+  }
+
+  // Set the old queue to the new queue.
+  minplayer.queue = newqueue;
+
+  // Release the lock.
+  minplayer.lock = false;
+};
+
+/**
+ * Trigger a media event.
+ *
+ * @param {string} type The event type.
+ * @param {object} data The event data object.
+ * @return {object} The plugin object.
+ */
+minplayer.plugin.prototype.trigger = function(type, data) {
+  data = data || {};
+  data.plugin = this;
+
+  // Add this to our triggered array.
+  this.triggered[type] = data;
+
+  // Check to make sure the queue for this type exists.
+  if (this.queue.hasOwnProperty(type)) {
+
+    var i = 0, queue = {};
+
+    // Iterate through all the callbacks in this queue.
+    for (i in this.queue[type]) {
+
+      // Setup the event object, and call the callback.
+      queue = this.queue[type][i];
+      queue.callback({target: this, data: queue.data}, data);
+    }
+  }
+
+  // Return the plugin object.
+  return this;
+};
+
+/**
+ * Bind to a media event.
+ *
+ * @param {string} type The event type.
+ * @param {object} data The data to bind with the event.
+ * @param {function} fn The callback function.
+ * @return {object} The plugin object.
+ **/
+minplayer.plugin.prototype.bind = function(type, data, fn) {
+
+  // Allow the data to be the callback.
+  if (typeof data === 'function') {
+    fn = data;
+    data = null;
+  }
+
+  // You must bind to a specific event and have a callback.
+  if (!type || !fn) {
+    return;
+  }
+
+  // Initialize the queue for this type.
+  this.queue[type] = this.queue[type] || [];
+
+  // Unbind any existing equivalent events.
+  this.unbind(type, fn);
+
+  // Now add this event to the queue.
+  this.queue[type].push({
+    callback: fn,
+    data: data
+  });
+
+  // Now see if this event has already been triggered.
+  if (this.triggered[type]) {
+
+    // Go ahead and trigger the event.
+    fn({target: this, data: data}, this.triggered[type]);
+  }
+
+  // Return the plugin.
+  return this;
+};
+
+/**
+ * Unbind a media event.
+ *
+ * @param {string} type The event type.
+ * @param {function} fn The callback function.
+ * @return {object} The plugin object.
+ **/
+minplayer.plugin.prototype.unbind = function(type, fn) {
+
+  // If this is locked then try again after 10ms.
+  if (this.lock) {
+    setTimeout((function(plugin) {
+      return function() {
+        plugin.unbind(type, fn);
+      };
+    })(this), 10);
+  }
+
+  // Set the lock.
+  this.lock = true;
+
+  if (!type) {
+    this.queue = {};
+  }
+  else if (!fn) {
+    this.queue[type] = [];
+  }
+  else {
+    // Iterate through all the callbacks and search for equal callbacks.
+    var i = 0, queue = {};
+    for (i in this.queue[type]) {
+      if (this.queue[type][i].callback === fn) {
+        queue = this.queue[type].splice(1, 1);
+        delete queue;
+      }
+    }
+  }
+
+  // Reset the lock.
+  this.lock = false;
+
+  // Return the plugin.
+  return this;
+};
+
+/**
+ * Adds an item to the queue.
+ *
+ * @param {object} context The context which this is called within.
+ * @param {string} event The event to trigger on.
+ * @param {string} id The player ID.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the event occurs.
+ */
+minplayer.addQueue = function(context, event, id, plugin, callback) {
+
+  // See if it is locked...
+  if (!minplayer.lock) {
+    minplayer.queue.push({
+      context: context,
+      id: id,
+      event: event,
+      plugin: plugin,
+      callback: callback
+    });
+  }
+  else {
+
+    // If so, then try again after 10 milliseconds.
+    setTimeout(function() {
+      minplayer.addQueue(context, id, event, plugin, callback);
+    }, 10);
+  }
+};
+
+/**
+ * Binds an event to a plugin instance, and if it doesn't exist, then caches
+ * it for a later time.
+ *
+ * @param {string} event The event to trigger on.
+ * @param {string} id The player ID.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the event occurs.
+ * @return {boolean} If the bind was successful.
+ * @this The object in context who called this method.
+ */
+minplayer.bind = function(event, id, plugin, callback) {
+
+  // If no callback exists, then just return false.
+  if (!callback) {
+    return false;
+  }
+
+  // Get the plugins.
+  var inst = minplayer.plugins;
+
+  // See if this plugin exists.
+  if (inst[id][plugin]) {
+
+    // If so, then bind the event to this plugin.
+    inst[id][plugin].bind(event, {context: this}, function(event, data) {
+      callback.call(event.data.context, data.plugin);
+    });
+    return true;
+  }
+
+  // If not, then add it to the queue to bind later.
+  minplayer.addQueue(this, event, id, plugin, callback);
+
+  // Return that this wasn't handled.
+  return false;
+};
+
+/**
+ * The main API for minPlayer.
+ *
+ * Provided that this function takes three parameters, there are 8 different
+ * ways to use this api.
+ *
+ *   id (0x100) - You want a specific player.
+ *   plugin (0x010) - You want a specific plugin.
+ *   callback (0x001) - You only want it when it is ready.
+ *
+ *   000 - You want all plugins from all players, ready or not.
+ *
+ *          var plugins = minplayer.get();
+ *
+ *   001 - You want all plugins from all players, but only when ready.
+ *
+ *          minplayer.get(function(plugin) {
+ *            // Code goes here.
+ *          });
+ *
+ *   010 - You want a specific plugin from all players, ready or not...
+ *
+ *          var medias = minplayer.get(null, 'media');
+ *
+ *   011 - You want a specific plugin from all players, but only when ready.
+ *
+ *          minplayer.get('player', function(player) {
+ *            // Code goes here.
+ *          });
+ *
+ *   100 - You want all plugins from a specific player, ready or not.
+ *
+ *          var plugins = minplayer.get('player_id');
+ *
+ *   101 - You want all plugins from a specific player, but only when ready.
+ *
+ *          minplayer.get('player_id', null, function(plugin) {
+ *            // Code goes here.
+ *          });
+ *
+ *   110 - You want a specific plugin from a specific player, ready or not.
+ *
+ *          var plugin = minplayer.get('player_id', 'media');
+ *
+ *   111 - You want a specific plugin from a specific player, only when ready.
+ *
+ *          minplayer.get('player_id', 'media', function(media) {
+ *            // Code goes here.
+ *          });
+ *
+ * @this The context in which this function was called.
+ * @param {string} id The ID of the widget to get the plugins from.
+ * @param {string} plugin The name of the plugin.
+ * @param {function} callback Called when the plugin is ready.
+ * @return {object} The plugin object if it is immediately available.
+ */
+minplayer.get = function(id, plugin, callback) {
+
+  // Normalize the arguments for a better interface.
+  if (typeof id === 'function') {
+    callback = id;
+    plugin = id = null;
+  }
+
+  if (typeof plugin === 'function') {
+    callback = plugin;
+    plugin = id;
+    id = null;
+  }
+
+  // Make sure the callback is a callback.
+  callback = (typeof callback === 'function') ? callback : null;
+
+  // Get the plugins.
+  var plugins = minplayer.plugins;
+
+  // 0x000
+  if (!id && !plugin && !callback) {
+    return plugins;
+  }
+  // 0x100
+  else if (id && !plugin && !callback) {
+    return plugins[id];
+  }
+  // 0x110
+  else if (id && plugin && !callback) {
+    return plugins[id][plugin];
+  }
+  // 0x111
+  else if (id && plugin && callback) {
+    minplayer.bind.call(this, 'ready', id, plugin, callback);
+  }
+  // 0x011
+  else if (!id && plugin && callback) {
+    for (var id in plugins) {
+      minplayer.bind.call(this, 'ready', id, plugin, callback);
+    }
+  }
+  // 0x101
+  else if (id && !plugin && callback) {
+    for (var plugin in plugins[id]) {
+      minplayer.bind.call(this, 'ready', id, plugin, callback);
+    }
+  }
+  // 0x010
+  else if (!id && plugin && !callback) {
+    var plugin_types = {};
+    for (var id in plugins) {
+      if (plugins.hasOwnProperty(id) && plugins[id].hasOwnProperty(plugin)) {
+        plugin_types[id] = plugins[id][plugin];
+      }
+    }
+    return plugin_types;
+  }
+  // 0x001
+  else {
+    for (var id in plugins) {
+      for (var plugin in plugins[id]) {
+        minplayer.bind.call(this, 'ready', id, plugin, callback);
+      }
+    }
+  }
+};
diff --git a/core/modules/file/player/templates/default/css/images/loader.gif b/core/modules/file/player/templates/default/css/images/loader.gif
new file mode 100644
index 0000000000000000000000000000000000000000..5e2d16730415c52b18d085af4b497b6f9d009666
GIT binary patch
literal 404
zcmZ?wbhEHb)Mnsj_{hL8bLPynw6yyAdLXIzpWDwhB-q(8z|~04fSHkjfkE+~lygyP
zVo7R>LV0FMhC*UiVnt4VVv1g7URpkb;!hS%E}$wMAZ7p=$iQUO(#LUn+RYoypO11$
z-wXSEy7hrsTSVl-H1*nhv-U0LN!Rtf-hN8&*OARX?RG3sF!B)vT7qee?Gd0c3jB%5
z8)vl~UsLmWM&iBiJt;G0%s;iz%h{_yX9s)s*^O&os_<=MOcjyJkN8yEcgpYbqggsh
zLC4o)HxcA81E7g3XJtj-$$!MpCA_`zVP(&fD+^Za;#<aj=(SI>S?BYU=U)B{nl)pM
z=^29__fs!F%><gbVjWf!9iU#FF=ZFKblt{ZJ5zmDn9O&V3)Cu6Ke}$^Z@!IYv$xLe
m|GVk&#1!Y)x6ib_%1*cn3+zcyIwv6di%Eom!5S29U;qH8Zk3+^

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/templates/default/css/images/pause-icon.png b/core/modules/file/player/templates/default/css/images/pause-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..17874391a349a0a5296e606856e8a762664c2eab
GIT binary patch
literal 201
zcmeAS@N?(olHy`uVBq!ia0vp^Vj#@H1|*Mc$*~4fk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*D5XvOQfKLn>}1{rUgj{_y7X^AaBzH8nLCT~T0GlW3ke@guXq
zfA_<?9C#+PKlIVb;yZjL!F0y0gewmMn_uP{Y-91$OkfmTkmJiCu$b-e1Acis0Uh>^
wK;v0jZoG1NY?~D}vUUX6%XV=xH83zUeEFs*^2YV9Fwj~CPgg&ebxsLQ0FS3aNdN!<

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/templates/default/css/images/play-icon.png b/core/modules/file/player/templates/default/css/images/play-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..71a34135e4e77734e6a80e0bc72ec81e067e65e0
GIT binary patch
literal 375
zcmV--0f_#IP)<h;3K|Lk000e1NJLTq000&M000&U1^@s6#I$TX0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUz8A(JzRCwBAeERe$11$g(h+t%7>;htG
zAZDNjh8qk7X+V4rh$jQFG}T-T1#Cc^1H`wX7D!OT;9p2$oKOp3J`knE;O|)EU=}<C
z;t8Z$z(j-^kOlcr3wnvQfQbZ0fGjA21`)^tA!->613XX*KtAZgWdRcf5f8GU6ly^`
zx&=(I1Wlm@6;KOWKo)?^WcmO9Keci(%m>UsT*LC=!v~Py7YYsi3&e|oxCw~wg9KQR
zB*+CTfw&%sZz2n_P+;IDke7k@GB!za4Bibj@Dx5pq!@f0h|7TZ2(@zFSs-=;Vk=?|
zC1fxt?1F&U1nPZ~0Jc;CirrRd@*x|*3<jm+N6>V*fWqX5Vlc>s`_Kw}iU2@>0RY83
VIH3}Z+z<c&002ovPDHLkV1n-Pi2eWo

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/templates/default/css/images/volume-full-icon.png b/core/modules/file/player/templates/default/css/images/volume-full-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..b0bfa43a5513f6ea766c86bc5445e81703e950f7
GIT binary patch
literal 666
zcmV;L0%iS)P)<h;3K|Lk000e1NJLTq000&M000&U1^@s6#I$TX0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU!JV``BRCwC7l}$)gQ547Ly?JI92|-ag
zGY<46&PLj}Nl;o8(MD=fP_DAt)owOIYG8r1Y*Xn<K?zDK=);X0gG2-gnifGZA4sIo
z#6&6eX8N7++?Z@;dXK>ef9{?Cx%c<ZJ@?)>R-sS`Y{p|J5{a4ssZ?rrI-TzL2V4sj
z;5OT~?*@ax30|<zHyA(@6Ze-19Rb>HSyou!zQ8~)GHHRyCpX3-k;p68b#E6zw%y6t
z%l`#4=ujq;dFeRL2++M)-%SkvKJhEk4~N6?d_Mn1`XmrfCX-G@FcbS2G>49tiQU5Q
zMZ=~%fCp&`ByfPtPl+e=7T(@UYa!W;t4wOIv=WZz47vuSk+A~o0sI6njn|CM;60X%
z`vFa{<VR?n!R^&*PF<$~O=?|Fkac4;8vTX$T0FpQrW8N@9y78V)1~jCZBu(u!F&GH
zm>+(@@6p=&)Z)g9x2)j?Q{#ZgYh5~Mi$G-_a@8}x^9CHuX0u+vD<#*z8P#hUi$^V&
z%hhRYDHIA7!C%m4H6^&y!%KR#eTzP7-)#B^Q{y-~tZG4h=vx)&Idoq8Be7V_WhL9`
zA5(AEfPbK`D%pUW=qP$o0lcR5UO=PjotBfRrFmNIN=x13+aTBWli3_?r;yyP9<)lf
zJ7}+K>=`Rac=-t3)7m}Q;6F$2^l05d2Q}LPGr;lk)kJ5})-o~qR$S2j4YFPI12)fU
z8Bb2dCDet6N&`-y_U9p*C)>YnnYCGeroROk08v!bv_qh#qyPW_07*qoM6N<$f=>=J
A&;S4c

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/templates/default/css/images/volume-mute-icon.png b/core/modules/file/player/templates/default/css/images/volume-mute-icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..23979e323b2989b87cdea7527c913e0d532f7411
GIT binary patch
literal 331
zcmV-R0kr;!P)<h;3K|Lk000e1NJLTq000&M000&U1^@s6#I$TX0000PbVXQnQ*UN;
zcVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBUy?MXyIRCwBA{Qv(y11$g(1C7AoGWhZ1
z$5Kz8JdvZS!9YWknVFf-0^`OPpE?#23{+)gWSqjn!r}%M`bM#ff!?kLy7D9tyAkUU
z3>RO!c1@j^msb<WWCUU^CMKplpn+zj1{t=Xs0SJp3G_DAQ^jwZB{xc4i!)Uana%%`
zYB2MM4<Cpz_zkHBzX#%1P&O+N3sNhL%Yax7iq(O*8i>D;YA_=);R#IJdO)fZh&_;m
zeYLc-wosJwfCgLwVoxA59f)7R97VN42x#~$AO*^WtAO|){xky&3Uct(t5;d@$uo{t
dO)vluU;xlmeHH0N4ZZ*X002ovPDHLkV1lGVf71W}

literal 0
HcmV?d00001

diff --git a/core/modules/file/player/templates/default/css/media_player_default.css b/core/modules/file/player/templates/default/css/media_player_default.css
new file mode 100644
index 0000000000000000000000000000000000000000..e3b228aefec11c7170efb7d1c37c41e985cfff0f
--- /dev/null
+++ b/core/modules/file/player/templates/default/css/media_player_default.css
@@ -0,0 +1,481 @@
+
+/* base styles */
+.media-player {}
+.media-player-play, .media-player-volume-button {
+  cursor: pointer;
+}
+.media-player-timer {
+  cursor: default;
+}
+
+.media-player {
+  position: relative;
+  background:#000;
+  border:1px solid #333;
+  font-family:"Trebuchet MS", Helvetica, sans-serif;
+  -moz-box-shadow:0px 5px 10px #333;/*no-important moz*/
+  -webkit-box-shadow:0px 5px 10px #333;/*no-important chrome*/
+}
+
+.media-player .media-player-error {
+  display:none;
+  position: absolute;
+  top: 80%;
+  left: 50%;
+  width: 320px;
+  height: 40px;
+  line-height: 40px;
+  margin: -20px 0 0 -160px;
+  text-align: center;
+  vertical-align: center;
+  border: none;
+  z-index:1000;
+  color: #fff;
+  opacity: 0.9;
+  border-radius: 10px;
+  -webkit-border-radius: 10px;
+  -moz-border-radius: 10px;
+  background: rgba(23, 35, 34, 0.9);
+  box-shadow: 2px 2px 4px #000;
+  -webkit-box-shadow: 2px 2px 4px #000;
+  -moz-box-shadow: 2px 2px 4px #000;
+}
+
+.media-player .media-player-display {
+  background-color:#000;
+  width:100%;
+  height:100%;
+}
+
+.media-player .media-player-display video {
+  width: 100%;
+  height: 100%;
+}
+
+.media-player .media-player-preview {
+  width:100%;
+  height:100%;
+  position:absolute;
+  z-index:1;
+}
+
+.media-player .media-player-preview.has-preview {
+  background-color: rgb(0, 0, 0);
+}
+
+.media-player .media-player-play-loader {
+  width:100%;
+  height:100%;
+  position:absolute;
+  z-index:2;
+  background: rgb(0, 0, 0);
+  background: rgba(0, 0, 0, 0.3);
+  filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#55000000, endColorstr=#55000000);
+  -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#55000000, endColorstr=#55000000)";
+}
+
+.media-player .media-player-play-loader .media-player-loader {
+  width:42px;
+  height:10px;
+  position: absolute;
+  z-index: 4;
+  top: 50%;
+  left: 50%;
+  margin: -5px 0 0 -21px;
+  text-align:center;
+  vertical-align:center;
+  background: url(images/loader.gif) no-repeat;
+}
+
+/* Big play button */
+.media-player .media-player-play-loader .media-player-big-play {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  width: 80px;
+  height: 80px;
+  margin: -40px 0 0 -40px;
+  text-align: center;
+  vertical-align: center;
+  cursor: pointer !important;
+  border: none;
+  opacity: 0.9;
+  z-index:3;
+  border-radius: 10px;
+  -webkit-border-radius: 10px;
+  -moz-border-radius: 10px;
+  background: rgba(23, 35, 34, 0.746094);
+  box-shadow: 2px 2px 4px #000;
+  -webkit-box-shadow: 2px 2px 4px #000;
+  -moz-box-shadow: 2px 2px 4px #000;
+}
+
+.media-player .media-player-play-loader .media-player-big-play span {
+  margin: 22px 0 0 48px;
+  border-left: 36px solid white;
+  border-top: 18px solid transparent;
+  border-bottom: 18px solid transparent;
+}
+
+.media-player .media-player-play-loader .media-player-big-play span {
+  display: block;
+  font-size: 0;
+  line-height: 0;
+  width: 0;
+  height: 0;
+  margin: 20px 0 0 23px;
+  border-left: 40px solid white;
+  border-top: 20px solid transparent;
+  border-bottom: 20px solid transparent;
+}
+
+.media-player.fullscreen, .media-player.fullscreen .media-player-display, .media-player.fullscreen .media-player-play-loader {
+  position: fixed;
+  left: 0;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  overflow: hidden;
+  z-index:1000;
+  width: 100% !important;
+  height: 100% !important;
+}
+
+.media-player.fullscreen .media-player-play-loader {
+  z-index:1001;
+}
+
+.media-player .media-player-controls {
+  position: absolute;
+  display: block;
+  z-index:3;
+  bottom:0px;
+  left:0px;
+  right:0px;
+  height:30px;
+  background-color:rgba(0,0,0,0.5);
+}
+
+.media-player-controls-left {
+  float:left;
+  width:30px;
+  height:26px;
+  margin: 2px 0;
+  border-right:1px solid #eee;
+}
+
+.media-player.fullscreen .media-player-controls-left {
+  width:40px;
+  border:none;
+}
+
+.media-player-controls-right {
+  float:right;
+  width:120px;
+  height:30px;
+}
+
+.media-player.fullscreen .media-player-controls-right {
+  width:110px;
+}
+
+.media-player-controls-mid {
+  position:absolute;
+  left:40px;
+  right:130px;
+  height:30px;
+}
+
+.media-player.fullscreen .media-player-controls-mid {
+  left:50px;
+}
+
+.media-player .media-player-play, .media-player .media-player-volume, .media-player .media-player-timer {
+  float: left;
+}
+
+/* play, pause */
+.media-player .media-player-play, .media-player .media-player-pause {
+  display: block;
+  width: 22px;
+  height: 22px;
+  margin:2px 0 0 4px;
+  opacity: 0.7;
+  -moz-transition: all 0.2s ease-in-out; /* Firefox */
+  -webkit-transition: all 0.2s ease-in-out; /* Safari and Chrome */
+  -o-transition: all 0.2s ease-in-out;  /* Opera */
+  transition: all 0.2s ease-in-out;
+}
+
+.media-player .media-player-play:hover, .media-player .media-player-pause:hover {
+  opacity: 1;
+}
+
+.media-player .media-player-play {
+  background: url(images/play-icon.png) no-repeat;
+}
+
+.media-player .media-player-pause {
+  background: url(images/pause-icon.png) no-repeat;
+  display:none;
+}
+
+/* seek */
+.media-player .media-player-seek {
+  position:relative;
+  height: 10px;
+  margin-top:9px;
+  border: 1px solid #494949;
+  -moz-border-radius:4px;
+  -webkit-border-radius:4px;
+  border-radius:4px;
+  background: #535353;
+  background-image: -moz-linear-gradient(top, #535353, #333333);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #535353),color-stop(1, #333333));
+  box-shadow: inset 0 -3px 3px #333333;
+}
+
+.media-player .media-player-seek .ui-slider-handle {
+  width: 15px;
+  height: 15px;
+  border: 1px solid #333;
+  top: -4px;
+  z-index:20px;
+  -moz-border-radius:10px;
+  -webkit-border-radius:10px;
+  border-radius:10px;
+  background: #e6e6e6;
+  background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));
+  box-shadow: inset 0 -3px 3px #d5d5d5;
+}
+
+.media-player .media-player-seek .ui-slider-handle.ui-state-hover {
+  background: #fff;
+}
+
+.media-player .media-player-seek .ui-slider-range {
+  -moz-border-radius:15px;
+  -webkit-border-radius:15px;
+  z-index:10px;
+  border-radius:15px;
+  background: #4cbae8;
+  background-image: -moz-linear-gradient(top, #4cbae8, #39a2ce);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #4cbae8),color-stop(1, #39a2ce));
+  box-shadow: inset 0 -3px 3px #39a2ce;
+}
+
+.media-player .media-player-progress {
+  -moz-border-radius:15px;
+  -webkit-border-radius:15px;
+  z-index:8px;
+  width:0px;
+  height:10px;
+  border-radius:15px;
+  background: #266580;
+  background-image: -moz-linear-gradient(top, #266580, #153A4A);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #266580),color-stop(1, #153A4A));
+  box-shadow: inset 0 -3px 3px #153A4A;
+}
+
+/* timer */
+.media-player .media-player-timer {
+  position:relative;
+  float:left;
+  color: #999;
+  margin-top:3px;
+  padding-right:6px;
+  font-size: 16px;
+  font-weight: bold;
+  border-right:1px solid #eee;
+}
+
+.media-player.fullscreen .media-player-timer {
+  border:none;
+  margin-top:4px;
+}
+
+/* volume */
+.media-player .media-player-volume {
+  position: absolute;
+  right:33px;
+  bottom:4px;
+  float:right;
+  overflow: hidden;
+  width: 20px;
+  height: 30px;
+  color: #fff;
+  padding: 0px 10px;
+  -moz-transition: all 0.1s ease-in-out; /* Firefox */
+  -webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
+  -o-transition: all 0.2s ease-in-out;  /* Opera */
+  transition: all 0.1s ease-in-out;
+}
+
+.media-player.fullscreen .media-player-volume {
+  right:40px;
+  bottom:13px;
+}
+
+.media-player .media-player-volume:hover {
+  height: 135px;
+  padding-top: 5px;
+}
+
+
+.media-player .media-player-volume:hover .media-player-volume-slider {
+  position: relative;
+  visibility: visible;
+  opacity: 1;
+}
+
+.media-player .media-player-volume-slider {
+  position: relative;
+  height: 100px;
+  width: 7px;
+  left: 4px;
+  visiblity: hidden;
+  opacity: 0;
+  border: 1px solid #444;
+  -moz-border-radius:15px;
+  -webkit-border-radius:15px;
+  border-radius:15px;
+  background: #535353;
+  background-image: -moz-linear-gradient(top, #535353, #333333);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #535353),color-stop(1, #333333));
+  box-shadow: inset 0 3px 3px #333333;
+  -moz-transition: all 0.1s ease-in-out; /* Firefox */
+  -webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
+  -o-transition: all 0.1s ease-in-out;  /* Opera */
+  transition: all 0.1s ease-in-out;
+}
+
+.media-player .media-player-volume-slider .ui-slider-handle {
+  width: 12px;
+  height: 12px;
+  left: -4px;
+  margin-bottom:-0.6em;
+  margin-left:0;
+  border: 1px solid #333;
+  -moz-border-radius:10px;
+  -webkit-border-radius:10px;
+  border-radius:10px;
+  background: #e6e6e6;
+  background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));
+
+  box-shadow: inset 0 3px 3px #d5d5d5;
+}
+
+.media-player .media-player-volume-slider .ui-slider-handle.ui-state-hover {
+  background: #fff;
+}
+
+.media-player .media-player-volume-slider .ui-slider-range {
+  -moz-border-radius:15px;
+  -webkit-border-radius:15px;
+  border-radius:15px;
+  background: #e6e6e6;
+  background-image: -moz-linear-gradient(top, #e6e6e6, #d5d5d5);
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #e6e6e6),color-stop(1, #d5d5d5));
+  box-shadow: inset 0 3px 3px #d5d5d5;
+}
+
+/* volume button */
+
+.media-player .media-player-volume-button {
+  position: absolute;
+  bottom: 0px;
+  display: block;
+  width: 22px;
+  height: 22px;
+  background: url(images/volume-full-icon.png) no-repeat;
+  text-indent: -9999px;
+  opacity: 0.8;
+}
+
+.media-player .media-player-volume-button:hover {
+  opacity: 1;
+}
+
+.media-player .media-player-volume-mute {
+  background: url(images/volume-mute-icon.png) no-repeat;
+}
+
+/* Fullscreen button */
+.media-player .media-player-fullscreen {
+  position: absolute;
+  right:6px;
+  bottom:7px;
+  width: 22px;
+  height: 14px;
+  border:1px solid #aaa;
+}
+
+.media-player.fullscreen .media-player-fullscreen {
+  right:14px;
+  bottom:16px;
+}
+
+.media-player .media-player-fullscreen-inner, .media-player.fullscreen .media-player-fullscreen:hover .media-player-fullscreen-inner {
+  position:absolute;
+  bottom:0;
+  width:16px;
+  height:8px;
+  background-color:#aaa;
+  -moz-transition: all 0.1s ease-in-out; /* Firefox */
+  -webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
+  -o-transition: all 0.1s ease-in-out;  /* Opera */
+  transition: all 0.1s ease-in-out;
+}
+
+.media-player .media-player-fullscreen:hover .media-player-fullscreen-inner, .media-player.fullscreen .media-player-fullscreen-inner {
+  width:20px;
+  height:12px;
+}
+
+.media-player.fullscreen .media-player-controls {
+  position: absolute;
+  z-index:1002;
+  width:500px;
+  left: 50%;
+  bottom:10px;
+  margin: 0 0 0 -260px;
+  padding: 10px;
+  border: 1px solid #2E2E2E;
+  -moz-border-radius: 5px; /* FF1+ */
+  -webkit-border-radius: 5px; /* Saf3+, Chrome */
+  border-radius: 5px; /* Opera 10.5, IE 9 */
+  background: #000000;
+  background-image: -moz-linear-gradient(top, #313131, #000000); /* FF3.6 */
+  background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0, #313131),color-stop(1, #000000)); /* Saf4+, Chrome */
+  box-shadow: inset 0 15px 35px #535353;
+  -moz-transition: all 0.1s ease-in-out; /* Firefox */
+  -webkit-transition: all 0.1s ease-in-out; /* Safari and Chrome */
+  -o-transition: all 0.1s ease-in-out;  /* Opera */
+  transition: all 0.1s ease-in-out;
+}
+
+
+/* needed jquery ui styles
+ * using these, we don't depend on jQuery UI's stylsheet
+*/
+.ui-slider-handle {
+  position: absolute;
+  z-index: 4;
+  display: block;
+  margin-left:-0.6em;
+  cursor: default;
+  outline: none;
+}
+
+.ui-slider-range {
+  display:block;
+  width:100%;
+  height:100%;
+  left:0;
+  bottom: 0;
+  border:0 none;
+  position:absolute;
+  z-index:3;
+}
\ No newline at end of file
diff --git a/core/modules/file/player/templates/default/js/minplayer.controller.default.js b/core/modules/file/player/templates/default/js/minplayer.controller.default.js
new file mode 100644
index 0000000000000000000000000000000000000000..5aaf4090ca139d018aa52751ba12287aea9d3b76
--- /dev/null
+++ b/core/modules/file/player/templates/default/js/minplayer.controller.default.js
@@ -0,0 +1,114 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+// Define the controller object.
+minplayer.controller = minplayer.controller || {};
+
+/**
+ * Constructor for the minplayer.controller
+ */
+minplayer.controller["default"] = function(context, options) {
+
+  // The fade timer.
+  this.timer = 0;
+
+  // Derive from base controller
+  minplayer.controller.call(this, context, options);
+};
+
+/** Derive from controller. */
+minplayer.controller["default"].prototype = new minplayer.controller();
+minplayer.controller["default"].prototype.constructor = minplayer.controller["default"];
+
+/**
+ * @see minplayer.plugin#construct
+ */
+minplayer.controller["default"].prototype.construct = function() {
+  minplayer.controller.prototype.construct.call(this);
+  minplayer.get.call(this, this.options.id, null, function(plugin) {
+    plugin.bind('fullscreen', {obj:this}, function(event, full) {
+      event.data.obj.onFullScreen(full);
+    });
+  });
+}
+
+/**
+ * Trigger when we go into full screen.
+ */
+minplayer.controller["default"].prototype.onFullScreen = function(full) {
+  if (full) {
+
+    var _this = this;
+    var showThenHide = function() {
+      clearTimeout(_this.timer);
+      _this.display.show();
+      _this.timer = setTimeout(function () {
+        _this.display.hide('fast');
+      }, 5000);
+    };
+
+    // Bind when they move the mouse.
+    jQuery(document).bind('mousemove', showThenHide);
+    showThenHide();
+  }
+  else {
+
+    // Unbind the show then hide function.
+    this.display.show();
+    clearTimeout(this.timer);
+    jQuery(document).unbind('mousemove', showThenHide);
+  }
+};
+
+/**
+ * Return the display for this plugin.
+ */
+minplayer.controller["default"].prototype.getDisplay = function(context, options) {
+
+  // See if we need to build out the controller.
+  if (options.build) {
+
+    // Prepend the control template.
+    context.prepend('\
+    <div class="media-player-error"></div>\
+    <div class="media-player-controls">\
+      <div class="media-player-controls-left">\
+        <a class="media-player-play" title="Play"></a>\
+        <a class="media-player-pause" title="Pause"></a>\
+      </div>\
+      <div class="media-player-controls-right">\
+        <div class="media-player-timer">00:00</div>\
+        <div class="media-player-fullscreen">\
+          <div class="media-player-fullscreen-inner"></div>\
+        </div>\
+        <div class="media-player-volume">\
+          <div class="media-player-volume-slider"></div>\
+          <a class="media-player-volume-button" title="Mute/Unmute"></a>\
+        </div>\
+      </div>\
+      <div class="media-player-controls-mid">\
+        <div class="media-player-seek">\
+          <div class="media-player-progress"></div>\
+        </div>\
+      </div>\
+    </div>');
+  }
+
+  return jQuery('.media-player-controls', context);
+}
+
+// Return the elements
+minplayer.controller["default"].prototype.getElements = function() {
+  var elements = minplayer.controller.prototype.getElements.call(this);
+  var timer = jQuery(".media-player-timer", this.display);
+  return jQuery.extend(elements, {
+    play: jQuery(".media-player-play", this.display),
+    pause: jQuery(".media-player-pause", this.display),
+    fullscreen: jQuery(".media-player-fullscreen", this.display),
+    seek: jQuery(".media-player-seek", this.display),
+    progress: jQuery(".media-player-progress", this.display),
+    volume: jQuery(".media-player-volume-slider", this.display),
+    timer:timer,
+    duration:timer
+  });
+};
diff --git a/core/modules/file/player/templates/default/js/minplayer.default.js b/core/modules/file/player/templates/default/js/minplayer.default.js
new file mode 100644
index 0000000000000000000000000000000000000000..74a644c98ea1b05a25b01945c4c44eeeed0c4849
--- /dev/null
+++ b/core/modules/file/player/templates/default/js/minplayer.default.js
@@ -0,0 +1,60 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+// Default player.
+minplayer["default"] = function(context, options) {
+
+  // Derive from minplayer.
+  minplayer.call(this, context, options);
+};
+
+/**
+ * Define this template prototype.
+ */
+minplayer["default"].prototype = new minplayer();
+minplayer["default"].prototype.constructor = minplayer["default"];
+
+/**
+ * Return the display for this plugin.
+ */
+minplayer["default"].prototype.getDisplay = function(context, options) {
+
+  // Convert the context to jQuery object.
+  context = jQuery(context);
+
+  // If the tag is video or audio, then build out the player.
+  var tag = context.get(0).tagName.toLowerCase();
+  if (tag == 'video' || tag == 'audio') {
+
+    // Build out the player provided the base tag.
+    context = context.attr({
+      'id': options.id + '-player',
+      'class': 'media-player-media'
+    })
+    .wrap(jQuery(document.createElement('div')).attr({
+      'class': 'media-player-display'
+    })).parent('.media-player-display')
+    .wrap(jQuery(document.createElement('div')).attr({
+      'id': options.id,
+      'class': 'media-player'
+    })).parent('.media-player');
+
+    // Mark a flag that says this display needs to be built.
+    options.build = true;
+  }
+
+  return context;
+}
+
+// Get the elements for this player.
+minplayer["default"].prototype.getElements = function() {
+  var elements = minplayer.prototype.getElements.call(this);
+
+  // Return the jQuery elements.
+  return jQuery.extend(elements, {
+    player:this.display,
+    display:jQuery(".media-player-display", this.display),
+    media:jQuery("#" + this.options.id + "-player", this.display),
+    error:jQuery('.media-player-error', this.display)
+  });
+};
diff --git a/core/modules/file/player/templates/default/js/minplayer.playLoader.default.js b/core/modules/file/player/templates/default/js/minplayer.playLoader.default.js
new file mode 100644
index 0000000000000000000000000000000000000000..eb6066740a559fa16ce7d897c4a4d3af31602630
--- /dev/null
+++ b/core/modules/file/player/templates/default/js/minplayer.playLoader.default.js
@@ -0,0 +1,46 @@
+/** The minplayer namespace. */
+var minplayer = minplayer || {};
+
+// Define the busy object.
+minplayer.playLoader = minplayer.playLoader || {};
+
+// constructor.
+minplayer.playLoader["default"] = function(context, options) {
+
+  // Derive from busy
+  minplayer.playLoader.call(this, context, options);
+};
+
+// Define the prototype for all controllers.
+minplayer.playLoader["default"].prototype = new minplayer.playLoader();
+minplayer.playLoader["default"].prototype.constructor = minplayer.playLoader["default"];
+
+/**
+ * Return the display for this plugin.
+ */
+minplayer.playLoader["default"].prototype.getDisplay = function(context, options) {
+
+  // See if we need to build out the controller.
+  if (options.build) {
+
+    // Prepend the playloader template.
+    context.prepend('\
+    <div class="media-player-play-loader">\
+      <div class="media-player-big-play"><span></span></div>\
+      <div class="media-player-loader">&nbsp;</div>\
+      <div class="media-player-preview"></div>\
+    </div>');
+  }
+
+  return jQuery('.media-player-play-loader', context);
+}
+
+// Return the elements
+minplayer.playLoader["default"].prototype.getElements = function() {
+  var elements = minplayer.playLoader.prototype.getElements.call(this);
+  return jQuery.extend(elements, {
+    busy:jQuery(".media-player-loader", this.display),
+    bigPlay:jQuery(".media-player-big-play", this.display),
+    preview:jQuery(".media-player-preview", this.display)
+  });
+};
diff --git a/core/modules/file/player/templates/default/media_player_default.tpl.php b/core/modules/file/player/templates/default/media_player_default.tpl.php
new file mode 100644
index 0000000000000000000000000000000000000000..b39ce953d36e1d5308c8085f9351f2f2f662144c
--- /dev/null
+++ b/core/modules/file/player/templates/default/media_player_default.tpl.php
@@ -0,0 +1,32 @@
+<div id="<?php print $settings['id']; ?>" class="media-player" style="width:<?php print $settings['width']; ?>; height:<?php print $settings['height']; ?>;">
+  <div class="media-player-error"></div>
+  <div class="media-player-controls">
+    <div class="media-player-controls-left">
+      <a class="media-player-play" title="Play"></a>
+      <a class="media-player-pause" title="Pause"></a>
+    </div>
+    <div class="media-player-controls-right">
+      <div class="media-player-timer">00:00</div>
+      <div class="media-player-fullscreen">
+        <div class="media-player-fullscreen-inner"></div>
+      </div>
+      <div class="media-player-volume">
+        <div class="media-player-volume-slider"></div>
+        <a class="media-player-volume-button" title="Mute/Unmute"></a>
+      </div>
+    </div>
+    <div class="media-player-controls-mid">
+      <div class="media-player-seek">
+        <div class="media-player-progress"></div>
+      </div>
+    </div>
+  </div>
+  <div class="media-player-play-loader">
+    <div class="media-player-big-play"><span></span></div>
+    <div class="media-player-loader">&nbsp;</div>
+    <div class="media-player-preview"></div>
+  </div>
+  <div class="media-player-display">
+    <?php print $player; ?>
+  </div>
+</div>
\ No newline at end of file
diff --git a/core/modules/file/player/tools/README.md b/core/modules/file/player/tools/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..cca552e58f066b0b04b6e1a1364ac7d672f0486d
--- /dev/null
+++ b/core/modules/file/player/tools/README.md
@@ -0,0 +1,5 @@
+This is a tools folder used to run the makefile.  You can easily get all the
+necessary tools by navigating to the player folder within Terminal, and then
+type the following command.
+
+  sudo make -B tools
