commit 2b3c8cc1f29d4786c42d46dc793c1bcb40f657fd
Author: Assos Assos <assos+forge@centrale-marseille.fr>
Date:   Wed Jul 15 22:46:25 2015 +0200

    Weekly update of contrib modules

diff --git a/drupal7/sites/all/modules/file_entity/file_entity.admin.inc b/drupal7/sites/all/modules/file_entity/file_entity.admin.inc
index 0e09e451..41c7c93b 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.admin.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.admin.inc
@@ -331,6 +331,8 @@ function file_entity_admin_files() {
   $query = db_select('file_managed', 'fm')->extend('PagerDefault')->extend('TableSort');
   $query->leftJoin('file_usage', 'fu', 'fm.fid = fu.fid');
   $query->groupBy('fm.fid');
+  $query->groupBy('fm.uid');
+  $query->groupBy('fm.timestamp');
   $query->addExpression('SUM(fu.count)', 'total_count');
   file_entity_build_filter_query($query);
 
@@ -354,6 +356,7 @@ function file_entity_admin_files() {
   $options = array();
   foreach ($files as $file) {
     $file_type = file_type_load($file->type);
+    $account = isset($accounts[$file->uid]) ? $accounts[$file->uid] : NULL;
     $options[$file->fid] = array(
       'title' => array(
         'data' => array(
@@ -364,7 +367,7 @@ function file_entity_admin_files() {
       ),
       'type' => $file_type ? check_plain($file_type->label) : FILE_TYPE_NONE,
       'size' => format_size($file->filesize),
-      'author' => theme('username', array('account' => $accounts[$file->uid])),
+      'author' => theme('username', array('account' => $account)),
       'timestamp' => format_date($file->timestamp, 'short'),
       'usage' => format_plural((int) $result[$file->fid]->total_count, '1 place', '@count places'),
     );
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.field.inc b/drupal7/sites/all/modules/file_entity/file_entity.field.inc
index 2a3700c1..4b039b63 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.field.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.field.inc
@@ -36,6 +36,7 @@ function file_entity_field_formatter_info() {
       'controls' => TRUE,
       'autoplay' => FALSE,
       'loop' => FALSE,
+      'preload' => '',
       'multiple_file_behavior' => 'tags',
     ),
     'file formatter' => array(
@@ -53,6 +54,7 @@ function file_entity_field_formatter_info() {
       'muted' => FALSE,
       'width' => NULL,
       'height' => NULL,
+      'preload' => '',
       'multiple_file_behavior' => 'tags',
     ),
     'file formatter' => array(
@@ -131,6 +133,13 @@ function file_entity_field_formatter_settings_form($field, $instance, $view_mode
       '#type' => 'checkbox',
       '#default_value' => $settings['loop'],
     );
+    $element['preload'] = array(
+      '#title' => t('Preload'),
+      '#type' => 'select',
+      '#default_value' => $settings['preload'],
+      '#options' => drupal_map_assoc(array('none', 'auto', 'metadata')),
+      '#empty_option' => 'unspecified',
+    );
     $element['multiple_file_behavior'] = array(
       '#title' => t('Display of multiple files'),
       '#type' => 'radios',
@@ -181,6 +190,13 @@ function file_entity_field_formatter_settings_form($field, $instance, $view_mode
       '#maxlength' => 5,
       '#field_suffix' => t('pixels'),
     );
+    $element['preload'] = array(
+      '#title' => t('Preload'),
+      '#type' => 'select',
+      '#default_value' => $settings['preload'],
+      '#options' => drupal_map_assoc(array('none', 'auto', 'metadata')),
+      '#empty_option' => 'unspecified',
+    );
     $element['multiple_file_behavior'] = array(
       '#title' => t('Display of multiple files'),
       '#type' => 'radios',
@@ -222,6 +238,9 @@ function file_entity_field_formatter_settings_summary($field, $instance, $view_m
     if (isset($settings['loop'])) {
       $summary[] = t('Loop: %loop', array('%loop' => $settings['loop'] ? t('yes') : t('no')));
     }
+    if (!empty($settings['preload'])) {
+      $summary[] = t('Preload: %preload', array('%preload' => $settings['preload']));
+    }
     if (isset($settings['multiple_file_behavior'])) {
       $summary[] = t('Multiple files: %multiple', array('%multiple' => $settings['multiple_file_behavior']));
     }
@@ -242,6 +261,9 @@ function file_entity_field_formatter_settings_summary($field, $instance, $view_m
     if ($settings['width'] && $settings['height']) {
       $summary[] = t('Size: %width x %height', array('%width' => $settings['width'], '%height' => $settings['height']));
     }
+    if (!empty($settings['preload'])) {
+      $summary[] = t('Preload: %preload', array('%preload' => $settings['preload']));
+    }
     if (isset($settings['multiple_file_behavior'])) {
       $summary[] = t('Multiple files: %multiple', array('%multiple' => $settings['multiple_file_behavior']));
     }
@@ -357,6 +379,7 @@ function file_entity_field_formatter_view($entity_type, $entity, $field, $instan
         '#controls' => $settings['controls'],
         '#autoplay' => $settings['autoplay'],
         '#loop' => $settings['loop'],
+        '#preload' => $settings['preload'],
       );
     }
   }
@@ -394,6 +417,7 @@ function file_entity_field_formatter_view($entity_type, $entity, $field, $instan
         '#muted' => $settings['muted'],
         '#width' => $settings['width'],
         '#height' => $settings['height'],
+        '#preload' => $settings['preload'],
       );
     }
   }
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.file.inc b/drupal7/sites/all/modules/file_entity/file_entity.file.inc
index 74feaa6f..c9aab5c0 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.file.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.file.inc
@@ -166,6 +166,7 @@ function file_entity_file_mimetype_mapping_alter(&$mapping) {
  * Implements hook_file_load().
  */
 function file_entity_file_load($files) {
+  // Add alt and title text to images.
   $alt = variable_get('file_entity_alt', '[file:field_file_image_alt_text]');
   $title = variable_get('file_entity_title', '[file:field_file_image_title_text]');
 
@@ -179,17 +180,35 @@ function file_entity_file_load($files) {
 
     // Load alt and title text from fields.
     if (!empty($alt)) {
-      $file->alt = token_replace($alt, array('file' => $file), $replace_options);
+      $output = token_replace($alt, array('file' => $file), $replace_options);
+
+      // @todo Remove once https://www.drupal.org/node/1713164 is fixed.
+      // There is currently no way to get the raw alt text returned from the
+      // token so we revert the encoding done during tokenization.
+      $file->alt = decode_entities($output);
     }
     if (!empty($title)) {
-      $file->title = token_replace($title, array('file' => $file), $replace_options);
+      $output = token_replace($title, array('file' => $file), $replace_options);
+
+      // @todo Remove once https://www.drupal.org/node/1713164 is fixed.
+      // There is currently no way to get the raw title text returned from the
+      // token so we revert the encoding done during tokenization.
+      $file->title = decode_entities($output);
     }
   }
 
   // Load and unserialize metadata.
   $results = db_query("SELECT * FROM {file_metadata} WHERE fid IN (:fids)", array(':fids' => array_keys($files)));
+
   foreach ($results as $result) {
-    $files[$result->fid]->metadata[$result->name] = unserialize($result->value);
+    $name = $result->name;
+
+    // image.module required height and width to be properties of the file.
+    if ($name == 'height' || $name == 'width') {
+      $files[$result->fid]->$name = unserialize($result->value);
+    }
+
+    $files[$result->fid]->metadata[$name] = unserialize($result->value);
   }
 }
 
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.file_default_displays.inc b/drupal7/sites/all/modules/file_entity/file_entity.file_default_displays.inc
index 74ca6609..ccf2376a 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.file_default_displays.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.file_default_displays.inc
@@ -99,7 +99,7 @@ function file_entity_file_default_displays() {
     $file_display = new stdClass();
     $file_display->api_version = 1;
     $file_display->name = 'image__default__file_field_image';
-    $file_display->weight = 49;
+    $file_display->weight = 48;
     $file_display->status = TRUE;
     $file_display->settings = array(
       'image_style' => '',
@@ -111,7 +111,7 @@ function file_entity_file_default_displays() {
     $file_display = new stdClass();
     $file_display->api_version = 1;
     $file_display->name = 'image__preview__file_field_image';
-    $file_display->weight = 49;
+    $file_display->weight = 48;
     $file_display->status = TRUE;
     $file_display->settings = array(
       'image_style' => 'thumbnail',
@@ -123,7 +123,7 @@ function file_entity_file_default_displays() {
     $file_display = new stdClass();
     $file_display->api_version = 1;
     $file_display->name = 'image__teaser__file_field_image';
-    $file_display->weight = 49;
+    $file_display->weight = 48;
     $file_display->status = TRUE;
     $file_display->settings = array(
       'image_style' => 'medium',
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.info b/drupal7/sites/all/modules/file_entity/file_entity.info
index a34997e6..a6c3a15d 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.info
+++ b/drupal7/sites/all/modules/file_entity/file_entity.info
@@ -1,11 +1,15 @@
-name = File entity
+name = File Entity
 description = "Extends Drupal file entities to be fieldable and viewable."
 package = Media
 core = 7.x
+
 dependencies[] = field
 dependencies[] = file
 dependencies[] = ctools
 dependencies[] = system (>=7.9)
+
+test_dependencies[] = token
+
 files[] = views/views_handler_argument_file_type.inc
 files[] = views/views_handler_field_file_rendered.inc
 files[] = views/views_handler_field_file_type.inc
@@ -20,14 +24,15 @@ files[] = views/views_handler_field_file_link_usage.inc
 files[] = views/views_plugin_row_file_rss.inc
 files[] = views/views_plugin_row_file_view.inc
 files[] = file_entity.test
+
 configure = admin/config/media/file-settings
 
 ; We have to add a fake version so Git checkouts do not fail Media dependencies
 version = 7.x-2.x-dev
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-beta1"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta2"
 core = "7.x"
 project = "file_entity"
-datestamp = "1412420930"
+datestamp = "1436896443"
 
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.install b/drupal7/sites/all/modules/file_entity/file_entity.install
index bbf4b246..feeb2e21 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.install
+++ b/drupal7/sites/all/modules/file_entity/file_entity.install
@@ -1070,3 +1070,12 @@ function file_entity_update_7215() {
   db_add_primary_key('file_metadata', array('fid', 'name'));
   db_drop_index('file_metadata', 'temp');
 }
+
+/**
+ * This update has been removed and will not run.
+ */
+function file_entity_update_7216() {
+  // This update function previously saved default file displays into the
+  // database. It has been removed due to reported problems and is better
+  // addressed by adding support for ctools default content to features.
+}
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.module b/drupal7/sites/all/modules/file_entity/file_entity.module
index 5d058e4c..f00dacc9 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.module
+++ b/drupal7/sites/all/modules/file_entity/file_entity.module
@@ -79,6 +79,9 @@ function file_entity_hook_info_alter(&$info) {
     // Miscellaneous hooks
     'file_mimetype_mapping_alter',
     'file_url_alter',
+    // Stream wrappers
+    'stream_wrappers',
+    'stream_wrappers_alter',
   );
   $info += array_fill_keys($hooks, array('group' => 'file'));
 }
@@ -875,6 +878,7 @@ function file_entity_theme() {
         'controls' => TRUE,
         'autoplay' => FALSE,
         'loop' => FALSE,
+        'preload' => NULL,
       ),
       'file' => 'file_entity.theme.inc',
     ),
@@ -887,6 +891,7 @@ function file_entity_theme() {
         'muted' => FALSE,
         'width' => NULL,
         'height' => NULL,
+        'preload' => NULL,
       ),
       'file' => 'file_entity.theme.inc',
     ),
@@ -954,8 +959,8 @@ function file_entity_entity_info_alter(&$entity_info) {
 
   // Ensure some of the Entity API callbacks are supported.
   $entity_info['file']['creation callback'] = 'entity_metadata_create_object';
-  $entity_info['file']['view callback'] = 'file_view_multiple';
-  $entity_info['file']['edit callback'] = 'file_entity_metadata_form_file';
+  $entity_info['file']['view callback'] = 'file_entity_metadata_view_file';
+  $entity_info['file']['form callback'] = 'file_entity_metadata_form_file';
   $entity_info['file']['access callback'] = 'file_entity_access';
 
   // Add integration with the Title module for file name replacement support.
@@ -1023,6 +1028,15 @@ function file_entity_uri($file) {
   return $uri;
 }
 
+/**
+ * Entity API callback to view files.
+ */
+function file_entity_metadata_view_file($entities, $view_mode = 'full', $langcode = NULL) {
+  $result = file_view_multiple($entities, $view_mode, 0, $langcode);
+  // Make sure to key the result with 'file' instead of 'files'.
+  return array('file' => reset($result));
+}
+
 /**
  * Entity API callback to get the form of a file entity.
  */
@@ -1036,10 +1050,9 @@ function file_entity_metadata_form_file($file) {
 /**
  * Implements hook_ctools_plugin_directory().
  */
-
-function file_entity_ctools_plugin_directory($module, $type) {
-  if ($module == 'ctools' && $type == 'content_types') {
-    return 'plugins/' . $type;
+function file_entity_ctools_plugin_directory($module, $plugin) {
+  if (in_array($module, array('panelizer', 'ctools', 'page_manager'))) {
+    return 'plugins/' . $plugin;
   }
 }
 
@@ -1491,6 +1504,7 @@ function file_entity_type_get_names() {
   $names = &drupal_static(__FUNCTION__);
 
   if (!isset($names)) {
+    $names = array();
     $info = entity_get_info('file');
     foreach ($info['bundles'] as $bundle => $bundle_info) {
       $names[$bundle] = $bundle_info['label'];
@@ -1563,11 +1577,11 @@ function file_entity_stream_wrappers_alter(&$wrappers) {
 /**
  * Implements hook_ctools_plugin_api().
  */
-function file_entity_ctools_plugin_api($owner, $api) {
-  if ($owner == 'file_entity' && $api == 'file_type') {
+function file_entity_ctools_plugin_api($module, $api) {
+  if (($module == 'file_entity' && $api == 'file_type') || ($module == 'page_manager' && $api == 'pages_default') || $module == 'panelizer') {
     return array('version' => 1);
   }
-  if ($owner == 'file_entity' && $api == 'file_default_displays') {
+  if ($module == 'file_entity' && $api == 'file_default_displays') {
     return array('version' => 1);
   }
 }
@@ -1955,7 +1969,7 @@ function file_entity_file_download($uri) {
     return file_get_content_headers($file);
   }
 
-  return -1;
+  return NULL;
 }
 
 /**
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.pages.inc b/drupal7/sites/all/modules/file_entity/file_entity.pages.inc
index a00245a9..17688fee 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.pages.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.pages.inc
@@ -165,7 +165,7 @@ function file_entity_add_upload_step_scheme($form, &$form_state, array $options
 
   // Remove any schemes not found in the instance settings.
   if (!empty($options['schemes'])) {
-    $schemes = array_intersect_key($schemes, $options['schemes']);
+    $schemes = array_intersect_key($schemes, array_flip($options['schemes']));
   }
 
   // Determine which scheme to use as the default value.
@@ -245,58 +245,54 @@ function file_entity_usage_page($file) {
   $rows = array();
   $occured_entities = array();
 
-  foreach (file_usage_list($file) as $module => $usage) {
-    $info = system_get_info('module', $module);
-
-    // There are cases where the actual entity doesn't exist.
-    // We have to handle this.
-    foreach ($usage as $entity_type => $entity_ids) {
+  // Determine all of the locations where a file is used, then loop through the
+  // occurrences and filter out any duplicates.
+  foreach (file_usage_list($file) as $module => $type) {
+    foreach ($type as $entity_type => $entity_ids) {
+      // There are cases where the actual entity doesn't exist.
+      // We have to handle this.
       $entity_info = entity_get_info($entity_type);
       $entities = empty($entity_info) ? NULL : entity_load($entity_type, array_keys($entity_ids));
 
       foreach ($entity_ids as $entity_id => $count) {
-        // If some other module already added this entity just sum all counts.
+        // If this entity has already been listed in the table, just add any
+        // additional usage to the total count column in the table row and
+        // continue on to the next iteration of the loop.
         if (isset($occured_entities[$entity_type][$entity_id])) {
           $rows[$occured_entities[$entity_type][$entity_id]][2] += $count;
           continue;
         }
 
+        // Retrieve the label and the URI of the entity.
         $label = empty($entities[$entity_id]) ? $module : entity_label($entity_type, $entities[$entity_id]);
         $entity_uri = empty($entities[$entity_id]) ? NULL : entity_uri($entity_type, $entities[$entity_id]);
 
-        // Some entities do not have URL.
+        // Link the label to the URI when possible.
         if (empty($entity_uri)) {
-          $rows[] = array(check_plain($label), $entity_type, $module, $count);
+          $entity = check_plain($label);
         }
         else {
-          $uri = $entity_uri['path'];
-          $rows[] = array(l($label, $uri), $entity_type, $module, $count);
+          $entity = l($label, $entity_uri['path']);
         }
 
+        $rows[] = array($entity, $entity_type, $count);
+
+        // Record the occurrence of the entity to ensure that it isn't listed in
+        // the table again.
         $occured_entities[$entity_type][$entity_id] = count($rows) - 1;
       }
     }
   }
-  $header[] = array(
-    'data' => t('Entity'),
-  );
-  $header[] = array(
-    'data' => t('Entity type'),
-  );
-  $header[] = array(
-    'data' => t('Registering module'),
-  );
-  $header[] = array(
-    'data' => t('Use count'),
-  );
+
+  $header = array(t('Entity'), t('Entity type'), t('Use count'));
   $build['usage_table'] = array(
     '#theme' => 'table',
     '#header' => $header,
     '#rows' => $rows,
-    '#caption' => t('This table lists all of the places where @filename is used.',
-    array('@filename' => $file->filename)),
+    '#caption' => t('This table lists all of the places where @filename is used.', array('@filename' => $file->filename)),
     '#empty' => t('This file is not currently used.'),
   );
+
   return $build;
 }
 
@@ -428,7 +424,9 @@ function file_entity_add_upload_submit($form, &$form_state) {
     $file = file_load($form_state['storage']['upload']);
     if ($file) {
       if (file_uri_scheme($file->uri) != $form_state['storage']['scheme']) {
-        if ($moved_file = file_move($file, $form_state['storage']['scheme'] . '://' . file_uri_target($file->uri), FILE_EXISTS_RENAME)) {
+        $file_destination = $form_state['storage']['scheme'] . '://' . file_uri_target($file->uri);
+        $file_destination = file_stream_wrapper_uri_normalize($file_destination);
+        if ($moved_file = file_move($file, $file_destination, FILE_EXISTS_RENAME)) {
           // Only re-assign the file object if file_move() did not fail.
           $file = $moved_file;
         }
@@ -455,17 +453,13 @@ function file_entity_add_upload_submit($form, &$form_state) {
     }
 
     // Figure out destination.
-    if (isset($_GET['destination'])) {
-      $destination = drupal_get_destination();
-      unset($_GET['destination']);
-    }
-    elseif (user_access('administer files')) {
-      $destination = array('destination' => 'admin/content/file');
+    if (user_access('administer files')) {
+      $path = 'admin/content/file';
     }
     else {
-      $destination = array('destination' => 'file/' . $file->fid);
+      $path = 'file/' . $file->fid;
     }
-    $form_state['redirect'] = $destination['destination'];
+    $form_state['redirect'] = $path;
   }
   else {
     $form_state['rebuild'] = TRUE;
@@ -558,7 +552,6 @@ function file_entity_add_upload_multiple_submit($form, &$form_state) {
       $file->status = FILE_STATUS_PERMANENT;
       file_save($file);
 
-      $saved_files[] = $file;
       $form_state['files'][$file->fid] = $file;
     }
     else {
@@ -568,7 +561,7 @@ function file_entity_add_upload_multiple_submit($form, &$form_state) {
   }
 
   // Redirect to the file edit page.
-  if (file_entity_access('update', $file) && module_exists('multiform') && module_exists('media')) {
+  if (file_entity_access('update', $file) && module_exists('media_bulk_upload')) {
     $destination = array();
     if (isset($_GET['destination'])) {
       $destination = drupal_get_destination();
@@ -807,7 +800,7 @@ function file_entity_edit_submit($form, &$form_state) {
   if (!empty($form_state['values']['replace_upload'])) {
     $replacement = $form_state['values']['replace_upload'];
     // Move file from temp to permanent home.
-    $destination_uri = file_uri_scheme($file->uri) . '://' . file_uri_target($replacement->uri);
+    $destination_uri = rtrim($file->uri, drupal_basename($file->uri)) . drupal_basename($replacement->uri);
     $replace_mode = $destination_uri == $file->uri ? FILE_EXISTS_REPLACE : FILE_EXISTS_RENAME;
     if ($new_file_uri = file_unmanaged_copy($replacement->uri, $destination_uri, $replace_mode)) {
       // @todo Add watchdog() about replaced file here?
@@ -848,7 +841,9 @@ function file_entity_edit_submit($form, &$form_state) {
   }
 
   if (file_uri_scheme($file->uri) != $form_state['values']['scheme']) {
-    if ($moved_file = file_move($file, $form_state['values']['scheme'] . '://' . file_uri_target($file->uri), FILE_EXISTS_RENAME)) {
+    $file_destination = $form_state['storage']['scheme'] . '://' . file_uri_target($file->uri);
+    $file_destination = file_stream_wrapper_uri_normalize($file_destination);
+    if ($moved_file = file_move($file, $file_destination, FILE_EXISTS_RENAME)) {
       // Only re-assign the file object if file_move() did not fail.
       $file = $moved_file;
     }
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.test b/drupal7/sites/all/modules/file_entity/file_entity.test
index 4cc4b9a7..2c72cbd8 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.test
+++ b/drupal7/sites/all/modules/file_entity/file_entity.test
@@ -6,8 +6,6 @@
  */
 
 class FileEntityTestHelper extends DrupalWebTestCase {
-  protected $files = array();
-
   function setUp() {
     $modules = func_get_args();
     if (isset($modules[0]) && is_array($modules[0])) {
@@ -17,88 +15,6 @@ class FileEntityTestHelper extends DrupalWebTestCase {
     parent::setUp($modules);
   }
 
-  protected function setUpFiles($defaults = array()) {
-    // Populate defaults array.
-    $defaults += array(
-      'uid' => 1,
-      'status' => FILE_STATUS_PERMANENT,
-    );
-
-    $types = array('text', 'image');
-    foreach ($types as $type) {
-      foreach ($this->drupalGetTestFiles($type) as $file) {
-        foreach ($defaults as $key => $value) {
-          $file->$key = $value;
-        }
-        $this->files[$type][] = file_save($file);
-      }
-    }
-  }
-
-  protected function createFileType($overrides = array()) {
-    $type = new stdClass();
-    $type->type = 'test';
-    $type->label = "Test";
-    $type->description = '';
-    $type->mimetypes = array('image/jpeg', 'image/gif', 'image/png', 'image/tiff');
-
-    foreach ($overrides as $k => $v) {
-      $type->$k = $v;
-    }
-
-    file_type_save($type);
-    return $type;
-  }
-
-  /**
-   * Helper for testFileEntityPrivateDownloadAccess() test.
-   *
-   * Defines several cases for accesing private files.
-   *
-   * @return array
-   *   Array of associative arrays, each one having the next keys:
-   *   - "message" string with the assertion message.
-   *   - "permissions" array of permissions or NULL for anonymous user.
-   *   - "expect" expected HTTP response code.
-   *   - "owner" Optional boolean indicating if the user is a file owner.
-   */
-  protected function getPrivateDownloadAccessCases() {
-    return array(
-      array(
-        'message' => "File owners cannot download their own files unless they are granted the 'view own private files' permission.",
-        'permissions' => array(),
-        'expect' => 403,
-        'owner' => TRUE,
-      ),
-      array(
-        'message' => "File owners can download their own files as they have been granted the 'view own private files' permission.",
-        'permissions' => array('view own private files'),
-        'expect' => 200,
-        'owner' => TRUE,
-      ),
-      array(
-        'message' => "Anonymous users cannot download private files.",
-        'permissions' => NULL,
-        'expect' => 403,
-      ),
-      array(
-        'message' => "Authenticated users cannot download each other's private files.",
-        'permissions' => array(),
-        'expect' => 403,
-      ),
-      array(
-        'message' => "Users who can view public files are not able to download private files.",
-        'permissions' => array('view files'),
-        'expect' => 403,
-      ),
-      array(
-        'message' => "Users who bypass file access can download any file.",
-        'permissions' => array('bypass file access'),
-        'expect' => 200,
-      ),
-    );
-  }
-
   /**
    * Retrieves a sample file of the specified type.
    */
@@ -112,6 +28,13 @@ class FileEntityTestHelper extends DrupalWebTestCase {
     return $file;
   }
 
+  /**
+   * Retrieves the fid of the last inserted file.
+   */
+  function getLastFileId() {
+    return (int) db_query('SELECT MAX(fid) FROM {file_managed}')->fetchField();
+  }
+
   /**
    * Get a file from the database based on its filename.
    *
@@ -131,8 +54,6 @@ class FileEntityTestHelper extends DrupalWebTestCase {
   }
 
   protected function createFileEntity($settings = array()) {
-    $file = new stdClass();
-
     // Populate defaults array.
     $settings += array(
       'filepath' => 'Файл для тестирования ' . $this->randomName(), // Prefix with non-latin characters to ensure that all file-related tests work with international filenames.
@@ -181,6 +102,21 @@ class FileEntityTestHelper extends DrupalWebTestCase {
     return $file;
   }
 
+  protected function createFileType($overrides = array()) {
+    $type = new stdClass();
+    $type->type = 'test';
+    $type->label = "Test";
+    $type->description = '';
+    $type->mimetypes = array('image/jpeg', 'image/gif', 'image/png', 'image/tiff');
+
+    foreach ($overrides as $k => $v) {
+      $type->$k = $v;
+    }
+
+    file_type_save($type);
+    return $type;
+  }
+
   /**
    * Overrides DrupalWebTestCase::drupalGetToken() to support the hash salt.
    *
@@ -192,6 +128,9 @@ class FileEntityTestHelper extends DrupalWebTestCase {
   }
 }
 
+/**
+ * Tests file type classification functionality.
+ */
 class FileEntityFileTypeClassificationTestCase extends DrupalWebTestCase {
   public static function getInfo() {
     return array(
@@ -205,25 +144,6 @@ class FileEntityFileTypeClassificationTestCase extends DrupalWebTestCase {
     parent::setUp();
   }
 
-  /**
-   * Get the file type of a given file.
-   *
-   * @param $file
-   *   A file object.
-   *
-   * @return
-   *   The file's file type as a string.
-   */
-  function getFileType($file) {
-    $type = db_select('file_managed', 'fm')
-      ->fields('fm', array('type'))
-      ->condition('fid', $file->fid, '=')
-      ->execute()
-      ->fetchAssoc();
-
-    return $type;
-  }
-
   /**
    * Test that existing files are properly classified by file type.
    */
@@ -257,8 +177,30 @@ class FileEntityFileTypeClassificationTestCase extends DrupalWebTestCase {
     $file_type = $this->getFileType($image_file);
     $this->assertEqual($file_type['type'], 'image', t('The image file was properly assigned the Image file type.'));
   }
+
+  /**
+   * Get the file type of a given file.
+   *
+   * @param $file
+   *   A file object.
+   *
+   * @return
+   *   The file's file type as a string.
+   */
+  function getFileType($file) {
+    $type = db_select('file_managed', 'fm')
+      ->fields('fm', array('type'))
+      ->condition('fid', $file->fid, '=')
+      ->execute()
+      ->fetchAssoc();
+
+    return $type;
+  }
 }
 
+/**
+ * Tests basic file entity functionality.
+ */
 class FileEntityUnitTestCase extends FileEntityTestHelper {
   public static function getInfo() {
     return array(
@@ -268,11 +210,6 @@ class FileEntityUnitTestCase extends FileEntityTestHelper {
     );
   }
 
-  function setUp() {
-    parent::setUp();
-    $this->setUpFiles();
-  }
-
   /**
    * Regression tests for core issue http://drupal.org/node/1239376.
    */
@@ -289,8 +226,15 @@ class FileEntityUnitTestCase extends FileEntityTestHelper {
     }
   }
 
+  /**
+   * Tests basic file entity properties.
+   */
   function testFileEntity() {
-    $file = reset($this->files['text']);
+    // Save a raw file, turning it into a file entity.
+    $file = $this->getTestFile('text');
+    $file->uid = 1;
+    $file->status = FILE_STATUS_PERMANENT;
+    file_save($file);
 
     // Test entity ID, revision ID, and bundle.
     $ids = entity_extract_ids('file', $file);
@@ -301,58 +245,64 @@ class FileEntityUnitTestCase extends FileEntityTestHelper {
     $this->assertEqual($uri['path'], "file/{$file->fid}");
   }
 
+  /**
+   * Tests storing image height and width as file metadata.
+   */
   function testImageDimensions() {
-    $files = array();
-    $text_fids = array();
     // Test hook_file_insert().
-    // Files have been saved as part of setup (in FileEntityTestHelper::setUpFiles).
-    foreach ($this->files['image'] as $file) {
-      $files[$file->fid] = $file->metadata;
-      $this->assertTrue(isset($file->metadata['height']), 'Image height retrieved on file_save() for an image file.');
-      $this->assertTrue(isset($file->metadata['width']), 'Image width retrieved on file_save() for an image file.');
-    }
-    foreach ($this->files['text'] as $file) {
-      $text_fids[] = $file->fid;
-      $this->assertFalse(isset($file->metadata['height']), 'No image height retrieved on file_save() for an text file.');
-      $this->assertFalse(isset($file->metadata['width']), 'No image width retrieved on file_save() for an text file.');
-    }
+    $file = current($this->drupalGetTestFiles('image'));
+    $image_file = file_save($file);
+    $this->assertTrue(isset($image_file->metadata['height']), 'Image height retrieved on file_save() for an image file.');
+    $this->assertTrue(isset($image_file->metadata['width']), 'Image width retrieved on file_save() for an image file.');
+
+    $file = current($this->drupalGetTestFiles('text'));
+    $text_file = file_save($file);
+    $this->assertFalse(isset($text_file->metadata['height']), 'No image height retrieved on file_save() for an text file.');
+    $this->assertFalse(isset($text_file->metadata['width']), 'No image width retrieved on file_save() for an text file.');
 
     // Test hook_file_load().
     // Clear the cache and load fresh files objects to test file_load behavior.
     entity_get_controller('file')->resetCache();
-    foreach (file_load_multiple(array_keys($files)) as $file) {
-      $this->assertTrue(isset($file->metadata['height']), 'Image dimensions retrieved on file_load() for an image file.');
-      $this->assertTrue(isset($file->metadata['width']), 'Image dimensions retrieved on file_load() for an image file.');
-      $this->assertEqual($file->metadata['height'], $files[$file->fid]['height'], 'Loaded image height is equal to saved image height.');
-      $this->assertEqual($file->metadata['width'], $files[$file->fid]['width'], 'Loaded image width is equal to saved image width.');
-    }
-    foreach (file_load_multiple($text_fids) as $file) {
-      $this->assertFalse(isset($file->metadata['height']), 'No image height retrieved on file_load() for an text file.');
-      $this->assertFalse(isset($file->metadata['width']), 'No image width retrieved on file_load() for an text file.');
-    }
+
+    $file = file_load($image_file->fid);
+    $this->assertTrue(isset($file->metadata['height']), 'Image dimensions retrieved on file_load() for an image file.');
+    $this->assertTrue(isset($file->metadata['width']), 'Image dimensions retrieved on file_load() for an image file.');
+
+    $this->assertEqual($file->metadata['height'], $image_file->metadata['height'], 'Loaded image height is equal to saved image height.');
+    $this->assertEqual($file->metadata['width'], $image_file->metadata['width'], 'Loaded image width is equal to saved image width.');
+
+    $file = file_load($text_file->fid);
+    $this->assertFalse(isset($file->metadata['height']), 'No image height retrieved on file_load() for an text file.');
+    $this->assertFalse(isset($file->metadata['width']), 'No image width retrieved on file_load() for an text file.');
 
     // Test hook_file_update().
     // Load the first image file and resize it.
-    $image_files = array_keys($files);
-    $file = file_load(reset($image_files));
-    $image = image_load($file->uri);
-    image_resize($image, $file->metadata['width'] / 2, $file->metadata['height'] / 2);
+    $height = $image_file->metadata['width'] / 2;
+    $width = $image_file->metadata['height'] / 2;
+    $image = image_load($image_file->uri);
+    image_resize($image, $width, $height);
     image_save($image);
-    file_save($file);
-    $this->assertEqual($file->metadata['height'], $files[$file->fid]['height'] / 2, 'Image file height updated by file_save().');
-    $this->assertEqual($file->metadata['width'], $files[$file->fid]['width'] / 2, 'Image file width updated by file_save().');
+    file_save($image_file);
+
+    $this->assertEqual($image_file->metadata['height'], $height, 'Image file height updated by file_save().');
+    $this->assertEqual($image_file->metadata['width'], $width, 'Image file width updated by file_save().');
+
     // Clear the cache and reload the file.
     entity_get_controller('file')->resetCache();
-    $file = file_load($file->fid);
-    $this->assertEqual($file->metadata['height'], $files[$file->fid]['height'] / 2, 'Updated image height retrieved by file_load().');
-    $this->assertEqual($file->metadata['width'], $files[$file->fid]['width'] / 2, 'Updated image width retrieved by file_load().');
 
-    //Test hook_file_delete().
+    $file = file_load($image_file->fid);
+    $this->assertEqual($file->metadata['height'], $height, 'Updated image height retrieved by file_load().');
+    $this->assertEqual($file->metadata['width'], $width, 'Updated image width retrieved by file_load().');
+
+    // Verify that the image dimension metadata is removed on file deletion.
     file_delete($file, TRUE);
-    $this->assertFalse(db_query('SELECT COUNT(*) FROM {file_metadata} WHERE fid = :fid', array(':fid' => 'fid'))->fetchField(), 'Row deleted in {file_dimensions} on file_delete().');
+    $this->assertFalse(db_query('SELECT COUNT(*) FROM {file_metadata} WHERE fid = :fid', array(':fid' => 'fid'))->fetchField(), 'Row deleted in {file_metadata} on file_delete().');
   }
 }
 
+/**
+ * Tests editing existing file entities.
+ */
 class FileEntityEditTestCase extends FileEntityTestHelper {
   protected $web_user;
   protected $admin_user;
@@ -463,43 +413,228 @@ class FileEntityEditTestCase extends FileEntityTestHelper {
   }
 }
 
-class FileEntityCreationTestCase extends FileEntityTestHelper {
+/**
+ * Tests creating new file entities through the file upload wizard.
+ */
+class FileEntityUploadWizardTestCase extends FileEntityTestHelper {
   public static function getInfo() {
     return array(
-      'name' => 'File entity creation',
-      'description' => 'Create a file and test saving it.',
+      'name' => 'File entity upload wizard',
+      'description' => 'Upload a file using the multi-step wizard.',
       'group' => 'File entity',
+      'dependencies' => array('token'),
     );
   }
 
   function setUp() {
-    parent::setUp();
+    parent::setUp('token');
 
-    $web_user = $this->drupalCreateUser(array('create files', 'edit own document files'));
+    // Disable the private file system which is automatically enabled by
+    // DrupalTestCase so we can test the upload wizard correctly.
+    variable_del('file_private_path');
+
+    $web_user = $this->drupalCreateUser(array('create files', 'view own private files'));
     $this->drupalLogin($web_user);
   }
 
   /**
-   * Create a "document" file and verify its consistency in the database.
+   * Test the basic file upload wizard functionality.
    */
-  function testFileEntityCreation() {
+  function testFileEntityUploadWizardBasic() {
     $test_file = $this->getTestFile('text');
-    // Create a file.
+
+    // Step 1: Upload a basic document file.
     $edit = array();
     $edit['files[upload]'] = drupal_realpath($test_file->uri);
     $this->drupalPost('file/add', $edit, t('Next'));
 
-    // Step 2: Scheme selection
-    if ($this->xpath('//input[@name="scheme"]')) {
-      $this->drupalPost(NULL, array(), t('Next'));
-    }
+    // Check that the file exists in the database.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+    $this->assertTrue($file, t('File found in database.'));
 
     // Check that the document file has been uploaded.
-    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Document', '%name' => $test_file->filename)), t('Document file uploaded.'));
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Document', '%name' => $file->filename)), t('Document file uploaded.'));
+  }
+
+  /**
+   * Test the file upload wizard type step.
+   */
+  function testFileEntityUploadWizardTypes() {
+    $test_file = $this->getTestFile('text');
+
+    // Create multiple file types with the same mime types.
+    $this->createFileType(array('type' => 'document1', 'label' => 'Document 1', 'mimetypes' => array('text/plain')));
+    $this->createFileType(array('type' => 'document2', 'label' => 'Document 2', 'mimetypes' => array('text/plain')));
+
+    // Step 1: Upload a basic document file.
+    $edit = array();
+    $edit['files[upload]'] = drupal_realpath($test_file->uri);
+    $this->drupalPost('file/add', $edit, t('Next'));
+
+    // Step 2: File type selection.
+    $edit = array();
+    $edit['type'] = 'document2';
+    $this->drupalPost(NULL, $edit, t('Next'));
 
     // Check that the file exists in the database.
-    $file = $this->getFileByFilename($test_file->filename);
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+    $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the document file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Document 2', '%name' => $file->filename)), t('Document 2 file uploaded.'));
+  }
+
+  /**
+   * Test the file upload wizard scheme step.
+   */
+  function testFileEntityUploadWizardSchemes() {
+    $test_file = $this->getTestFile('text');
+
+    // Enable the private file system.
+    variable_set('file_private_path', $this->private_files_directory);
+
+    // Step 1: Upload a basic document file.
+    $edit = array();
+    $edit['files[upload]'] = drupal_realpath($test_file->uri);
+    $this->drupalPost('file/add', $edit, t('Next'));
+
+    // Step 3: Scheme selection.
+    $edit = array();
+    $edit['scheme'] = 'private';
+    $this->drupalPost(NULL, $edit, t('Next'));
+
+    // Check that the file exists in the database.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+    $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the document file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Document', '%name' => $file->filename)), t('Document file uploaded.'));
+  }
+
+  /**
+   * Test the file upload wizard field step.
+   */
+  function testFileEntityUploadWizardFields() {
+    $test_file = $this->getTestFile('image');
+    $filename = $this->randomName();
+    $alt = $this->randomName();
+    $title = $this->randomName();
+
+    // Step 1: Upload a basic image file.
+    $edit = array();
+    $edit['files[upload]'] = drupal_realpath($test_file->uri);
+    $this->drupalPost('file/add', $edit, t('Next'));
+
+    // Step 4: Attached fields.
+    $edit = array();
+    $edit['filename'] = $filename;
+    $edit['field_file_image_alt_text[' . LANGUAGE_NONE . '][0][value]'] = $alt;
+    $edit['field_file_image_title_text[' . LANGUAGE_NONE . '][0][value]'] = $title;
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Check that the file exists in the database.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
     $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the image file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Image', '%name' => $filename)), t('Image file uploaded.'));
+
+    // Check that the alt and title text was loaded from the fields.
+    $this->assertEqual($file->alt, $alt, t('Alt text was stored as file metadata.'));
+    $this->assertEqual($file->title, $title, t('Title text was stored as file metadata.'));
+  }
+
+  /**
+   * Test skipping each of the file upload wizard steps.
+   */
+  function testFileEntityUploadWizardStepSkipping() {
+    $test_file = $this->getTestFile('image');
+    $filename = $this->randomName();
+
+    // Ensure that the file is affected by every step.
+    variable_set('file_private_path', $this->private_files_directory);
+
+    $this->createFileType(array('type' => 'image1', 'label' => 'Image 1', 'mimetypes' => array('image/jpeg', 'image/gif', 'image/png', 'image/tiff')));
+    $this->createFileType(array('type' => 'image2', 'label' => 'Image 2', 'mimetypes' => array('image/jpeg', 'image/gif', 'image/png', 'image/tiff')));
+
+    $field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = array('field_name' => $field_name, 'type' => 'text');
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'file',
+      'bundle' => 'image2',
+      'label' => $this->randomName() . '_label',
+    );
+    field_create_instance($instance);
+
+    // Test skipping each upload wizard step.
+    foreach (array('types', 'schemes', 'fields') as $step) {
+      // Step to skip.
+      switch ($step) {
+        case 'types':
+          variable_set('file_entity_file_upload_wizard_skip_file_type', TRUE);
+          break;
+        case 'schemes':
+          variable_set('file_entity_file_upload_wizard_skip_scheme', TRUE);
+          break;
+        case 'fields':
+          variable_set('file_entity_file_upload_wizard_skip_fields', TRUE);
+          break;
+      }
+
+      // Step 1: Upload a basic image file.
+      $edit = array();
+      $edit['files[upload]'] = drupal_realpath($test_file->uri);
+      $this->drupalPost('file/add', $edit, t('Next'));
+
+      // Step 2: File type selection.
+      if ($step != 'types') {
+        $edit = array();
+        $edit['type'] = 'image2';
+        $this->drupalPost(NULL, $edit, t('Next'));
+      }
+
+      // Step 3: Scheme selection.
+      if ($step != 'schemes') {
+        $edit = array();
+        $edit['scheme'] = 'private';
+        $this->drupalPost(NULL, $edit, t('Next'));
+      }
+
+      // Step 4: Attached fields.
+      if ($step != 'fields') {
+        // Skipping file type selection essentially skips this step as well
+        // because the file will not be assigned a type so no fields will be
+        // available.
+        if ($step != 'types') {
+          $edit = array();
+          $edit['filename'] = $filename;
+          $edit[$field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName();
+          $this->drupalPost(NULL, $edit, t('Save'));
+        }
+      }
+
+      // Check that the file exists in the database.
+      $fid = $this->getLastFileId();
+      $file = file_load($fid);
+      $this->assertTrue($file, t('File found in database.'));
+
+      // Determine the file's file type.
+      $type = file_type_load($file->type);
+
+      // Check that the image file has been uploaded.
+      $this->assertRaw(t('!type %name was uploaded.', array('!type' => $type->label, '%name' => $file->filename)), t('Image file uploaded.'));
+
+      // Reset 'skip' variables.
+      variable_del('file_entity_file_upload_wizard_skip_file_type');
+      variable_del('file_entity_file_upload_wizard_skip_scheme');
+      variable_del('file_entity_file_upload_wizard_skip_fields');
+    }
   }
 }
 
@@ -585,11 +720,12 @@ class FileEntityAdminTestCase extends FileEntityTestHelper {
     $files['private_image'] = $this->createFileEntity(array('scheme' => 'private', 'uid' => $this->base_user_1->uid, 'type' => 'image'));
     $files['private_document'] = $this->createFileEntity(array('scheme' => 'private', 'uid' => $this->base_user_2->uid, 'type' => 'document'));
 
-    // Verify view, edit, and delete links for any file.
+    // Verify view, usage, edit, and delete links for any file.
     $this->drupalGet('admin/content/file');
     $this->assertResponse(200);
     foreach ($files as $file) {
       $this->assertLinkByHref('file/' . $file->fid);
+      $this->assertLinkByHref('file/' . $file->fid . '/usage');
       $this->assertLinkByHref('file/' . $file->fid . '/edit');
       $this->assertLinkByHref('file/' . $file->fid . '/delete');
       // Verify tableselect.
@@ -646,6 +782,7 @@ class FileEntityAdminTestCase extends FileEntityTestHelper {
     $this->assertResponse(200);
     foreach ($files as $file) {
       $this->assertLinkByHref('file/' . $file->fid);
+      $this->assertLinkByHref('file/' . $file->fid . '/usage');
       $this->assertLinkByHref('file/' . $file->fid . '/edit');
       $this->assertLinkByHref('file/' . $file->fid . '/delete');
     }
@@ -657,13 +794,194 @@ class FileEntityAdminTestCase extends FileEntityTestHelper {
     $this->assertResponse(200);
     foreach ($files as $file) {
       $this->assertLinkByHref('file/' . $file->fid);
+      $this->assertLinkByHref('file/' . $file->fid . '/usage');
       $this->assertLinkByHref('file/' . $file->fid . '/edit');
       $this->assertLinkByHref('file/' . $file->fid . '/delete');
     }
   }
 }
 
-class FileEntityReplaceTestCase extends FileEntityTestHelper {
+/**
+ * Tests the file usage page.
+ */
+class FileEntityUsageTestCase extends FileEntityTestHelper {
+  public static function getInfo() {
+    return array(
+      'name' => 'File entity usage',
+      'description' => 'Create a file and verify its usage.',
+      'group' => 'File entity',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    $web_user = $this->drupalCreateUser(array('create files', 'bypass file access', 'edit own article content'));
+    $this->drupalLogin($web_user);
+  }
+
+  /**
+   * Create a file and verify its usage information.
+   */
+  function testFileEntityUsagePage() {
+    $image_field = 'field_image';
+    $image = $this->getTestFile('image');
+
+    // Create a node, save it, then edit it to upload a file.
+    $edit = array(
+      "files[" . $image_field . "_" . LANGUAGE_NONE . "_0]" => drupal_realpath($image->uri),
+    );
+    $node = $this->drupalCreateNode(array('type' => 'article'));
+    $this->drupalPost('node/' . $node->nid . '/edit', $edit, t('Save'));
+
+    // Load the uploaded file.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+
+    // View the file's usage page.
+    $this->drupalGet('file/' . $file->fid . '/usage');
+
+    // Verify that a link to the entity is available.
+    $this->assertLink($node->title);
+    $this->assertLinkByHref('node/' . $node->nid);
+
+    // Verify that the entity type and use count information is also present.
+    $expected_values = array(
+      'type' => 'node',
+      'count' => 1,
+    );
+    foreach ($expected_values as $name => $value) {
+      $this->assertTrue($this->xpath('//table/tbody/tr/td[normalize-space(text())=:text]', array(':text' => $value)), t('File usage @name was found in the table.', array('@name' => $name)));
+    }
+
+    // Add a reference to the file from the same entity but registered by a
+    // different module to ensure that the usage count is incremented and no
+    // additional table rows are created.
+    file_usage_add($file, 'example_module', 'node', $node->nid, 2);
+
+    // Reload the page and verify that the expected values are present.
+    $this->drupalGet('file/' . $file->fid . '/usage');
+    $expected_values['count'] = 3;
+    foreach ($expected_values as $name => $value) {
+      $this->assertTrue($this->xpath('//table/tbody/tr/td[normalize-space(text())=:text]', array(':text' => $value)), t('File usage @name was found in the table.', array('@name' => $name)));
+    }
+
+    // Add a reference to the file from an entity that doesn't exist to ensure
+    // that this case is handled.
+    file_usage_add($file, 'test_module', 'imaginary', 1);
+
+    // Reload the page.
+    $this->drupalGet('file/' . $file->fid . '/usage');
+
+    // Verify that the module name is used in place of a link to the entity.
+    $this->assertNoLink('test_module');
+    $this->assertRaw('test_module', 'Module name used in place of link to the entity.');
+
+    // Verify that the entity type and use count information is also present.
+    $expected_values = array(
+      'type' => 'imaginary',
+      'count' => 1,
+    );
+    foreach ($expected_values as $name => $value) {
+      $this->assertTrue($this->xpath('//table/tbody/tr/td[normalize-space(text())=:text]', array(':text' => $value)), t('File usage @name was found in the table.', array('@name' => $name)));
+    }
+  }
+}
+
+/**
+ * Tests image alt and title text.
+ */
+class FileEntityAltTitleTestCase extends FileEntityTestHelper {
+  public static function getInfo() {
+    return array(
+      'name' => 'File entity alt and title text',
+      'description' => 'Create an image file with alt and title text.',
+      'group' => 'File entity',
+      'dependencies' => array('token'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp('token');
+
+    $web_user = $this->drupalCreateUser(array('create files', 'edit own image files'));
+    $this->drupalLogin($web_user);
+  }
+
+  /**
+   * Create an "image" file and verify its associated alt and title text.
+   */
+  function testFileEntityAltTitle() {
+    $test_file = $this->getTestFile('image');
+    $alt_field_name = 'field_file_image_alt_text'; // Name of the default alt text field added to the image file type.
+    $title_field_name = 'field_file_image_title_text'; // Name of the default title text field added to the image file type.
+
+    // Create a file.
+    $edit = array();
+    $edit['files[upload]'] = drupal_realpath($test_file->uri);
+    $this->drupalPost('file/add', $edit, t('Next'));
+
+    // Step 2: Scheme selection.
+    if ($this->xpath('//input[@name="scheme"]')) {
+      $this->drupalPost(NULL, array(), t('Next'));
+    }
+
+    // Step 3: Attached fields.
+    $alt = 'Quote&quot; Amp&amp; ' . 'Файл для тестирования ' . $this->randomName(); // Generate alt text containing HTML entities, spaces and non-latin characters.
+    $title = 'Quote&quot; Amp&amp; ' . 'Файл для тестирования ' . $this->randomName(); // Generate title text containing HTML entities, spaces and non-latin characters.
+
+    $edit = array();
+    $edit[$alt_field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $alt;
+    $edit[$title_field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $title;
+    $this->drupalPost(NULL, $edit, t('Save'));
+
+    // Check that the image file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Image', '%name' => $test_file->filename)), t('Image file uploaded.'));
+
+    // Check that the file exists in the database.
+    $file = $this->getFileByFilename($test_file->filename);
+    $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the alt and title text was loaded from the fields.
+    $this->assertEqual($file->alt, $alt, t('Alt text was stored as file metadata.'));
+    $this->assertEqual($file->title, $title, t('Title text was stored as file metadata.'));
+
+    // Verify that the alt and title text is present on the page.
+    $image_info = array(
+      'path' => $file->uri,
+      'alt' => $alt,
+      'title' => $title,
+      'width' => $file->width,
+      'height' => $file->height,
+    );
+    $default_output = theme('image', $image_info);
+    $this->assertRaw($default_output, 'Image displayed using user supplied alt and title attributes.');
+
+    // Verify that the alt and title text can be edited.
+    $new_alt = $this->randomName();
+    $new_title = $this->randomName();
+
+    $edit = array();
+    $edit[$alt_field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $new_alt;
+    $edit[$title_field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $new_title;
+    $this->drupalPost('file/' . $file->fid . '/edit', $edit, t('Save'));
+
+    $image_info = array(
+      'path' => $file->uri,
+      'alt' => $new_alt,
+      'title' => $new_title,
+      'width' => $file->width,
+      'height' => $file->height,
+    );
+    $default_output = theme('image', $image_info);
+    $this->assertRaw($default_output, 'Image displayed using updated alt and title attributes.');
+  }
+}
+
+/**
+ * Tests replacing the file associated with a file entity.
+ */
+class FileEntityReplaceTestCase extends FileEntityTestHelper {
   public static function getInfo() {
     return array(
       'name' => 'File replacement',
@@ -674,7 +992,6 @@ class FileEntityReplaceTestCase extends FileEntityTestHelper {
 
   function setUp() {
     parent::setUp();
-    $this->setUpFiles();
   }
 
   /**
@@ -683,7 +1000,7 @@ class FileEntityReplaceTestCase extends FileEntityTestHelper {
    */
   function testReplaceFile() {
     // Select the first text test file to use.
-    $file = reset($this->files['text']);
+    $file = $this->createFileEntity(array('type' => 'document'));
 
     // Create a user with file edit permissions.
     $user = $this->drupalCreateUser(array('edit any document files'));
@@ -697,9 +1014,9 @@ class FileEntityReplaceTestCase extends FileEntityTestHelper {
     $this->drupalPost(NULL, array(), t('Save'));
     $this->assertText(t('Document @file has been updated.', array('@file' => $file->filename)), 'File was updated without file upload.');
 
-    // Get the next text file to use as a replacement.
+    // Get a text file to use as a replacement.
     $original = clone $file;
-    $replacement = next($this->files['text']);
+    $replacement = $this->getTestFile('text');
 
     // Test that the file saves when uploading a replacement file.
     $edit = array();
@@ -718,7 +1035,7 @@ class FileEntityReplaceTestCase extends FileEntityTestHelper {
     $this->assertFalse(entity_load('file', FALSE, array('status' => 0)), 'Temporary file used for replacement was deleted.');
 
     // Get an image file.
-    $image = reset($this->files['image']);
+    $image = $this->getTestFile('image');
     $edit['files[replace_upload]'] = drupal_realpath($image->uri);
 
     // Test that validation works by uploading a non-text file as a replacement.
@@ -745,6 +1062,9 @@ class FileEntityReplaceTestCase extends FileEntityTestHelper {
   }
 }
 
+/**
+ * Tests file entity tokens.
+ */
 class FileEntityTokenTestCase extends FileEntityTestHelper {
   public static function getInfo() {
     return array(
@@ -756,25 +1076,26 @@ class FileEntityTokenTestCase extends FileEntityTestHelper {
 
   function setUp() {
     parent::setUp();
-    $this->setUpFiles();
   }
 
   function testFileEntityTokens() {
+    $file = $this->createFileEntity(array('type' => 'document'));
     $tokens = array(
       'type' => 'Document',
       'type:name' => 'Document',
       'type:machine-name' => 'document',
-      'type:count' => count($this->files['text']),
+      'type:count' => 1,
     );
-    $this->assertTokens('file', array('file' => $this->files['text'][0]), $tokens);
+    $this->assertTokens('file', array('file' => $file), $tokens);
 
+    $file = $this->createFileEntity(array('type' => 'image'));
     $tokens = array(
       'type' => 'Image',
       'type:name' => 'Image',
       'type:machine-name' => 'image',
-      'type:count' => count($this->files['image']),
+      'type:count' => 1,
     );
-    $this->assertTokens('file', array('file' => $this->files['image'][0]), $tokens);
+    $this->assertTokens('file', array('file' => $file), $tokens);
   }
 
   function assertTokens($type, array $data, array $tokens, array $options = array()) {
@@ -799,6 +1120,9 @@ class FileEntityTokenTestCase extends FileEntityTestHelper {
   }
 }
 
+/**
+ * Tests adding support for bundles to the core 'file' entity.
+ */
 class FileEntityTypeTestCase extends FileEntityTestHelper {
   public static function getInfo() {
     return array(
@@ -810,7 +1134,6 @@ class FileEntityTypeTestCase extends FileEntityTestHelper {
 
   function setUp() {
     parent::setUp();
-    $this->setUpFiles();
   }
 
   /**
@@ -836,148 +1159,6 @@ class FileEntityTypeTestCase extends FileEntityTestHelper {
     $this->assertEqual($loaded_type->label, $type_machine_label, "Was able to create a type and retreive it.");
   }
 
-
-  /**
-   * Ensures that the weight is respected when types are created.
-   * @return unknown_type
-   */
-  function testOrder() {
-//    $type = $this->createFileType(array('name' => 'last', 'label' => 'Last', 'weight' => 100));
-//    $type = $this->createFileType(array('name' => 'first', 'label' => 'First'));
-//    $types = media_type_get_types();
-//    $keys = array_keys($types);
-//    $this->assertTrue(isset($types['last']) && isset($types['first']), "Both types saved");
-//    $this->assertTrue(array_search('last', $keys) > array_search('first', $keys), 'Type which was supposed to be first came first');
-  }
-
-  /**
-   * Test view mode assignment.  Currently fails, don't know why.
-   * @return unknown_type
-   */
-  function testViewModesAssigned() {
-  }
-
-  /**
-   * Make sure candidates are presented in the case of multiple
-   * file types.
-   */
-  function testTypeWithCandidates() {
-    // Create multiple file types with the same mime types.
-    $types = array(
-      'image1' => $this->createFileType(array('type' => 'image1', 'label' => 'Image 1')),
-      'image2' => $this->createFileType(array('type' => 'image2', 'label' => 'Image 2'))
-    );
-
-    // Attach a text field to one of the file types.
-    $field = array(
-      'field_name' => drupal_strtolower($this->randomName()),
-      'type' => 'text',
-      'settings' => array(
-        'max_length' => 255,
-      )
-    );
-    field_create_field($field);
-    $instance = array(
-      'field_name' => $field['field_name'],
-      'entity_type' => 'file',
-      'bundle' => 'image2',
-      'widget' => array(
-        'type' => 'text_textfield',
-      ),
-      'display' => array(
-        'default' => array(
-          'type' => 'text_default',
-        ),
-      ),
-    );
-    field_create_instance($instance);
-
-    // Create a user with file creation access.
-    $user = $this->drupalCreateUser(array('create files'));
-    $this->drupalLogin($user);
-
-    // Step 1: Upload file
-    $file = reset($this->files['image']);
-    $edit = array();
-    $edit['files[upload]'] = drupal_realpath($file->uri);
-    $this->drupalPost('file/add', $edit, t('Next'));
-
-    // Step 2: Select file type candidate
-    $this->assertText('Image 1', 'File type candidate list item found.');
-    $this->assertText('Image 2', 'File type candidate list item found.');
-    $edit = array();
-    $edit['type'] = 'image2';
-    $this->drupalPost(NULL, $edit, t('Next'));
-
-    // Step 3: Select file scheme candidate
-    $this->assertText('Public local files served by the webserver.', 'File scheme candidate list item found.');
-    $this->assertText('Private local files served by Drupal.', 'File scheme candidate list item found.');
-    $edit = array();
-    $edit['scheme'] = 'public';
-    $this->drupalPost(NULL, $edit, t('Next'));
-
-    // Step 4: Complete field widgets
-    $langcode = LANGUAGE_NONE;
-    $edit = array();
-    $edit["{$field['field_name']}[$langcode][0][value]"] = $this->randomName();
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Image 2', '%name' => $file->filename)), t('Image 2 file updated.'));
-    $this->assertText($field['field_name'], 'File text field was found.');
-  }
-
-  /**
-   * Make sure no candidates appear when only one mime type is available.
-   * NOTE: Depends on file_entity.module default 'image' type.
-   */
-  function testTypeWithoutCandidates() {
-    // Attach a text field to the default image file type.
-    $field = array(
-      'field_name' => drupal_strtolower($this->randomName()),
-      'type' => 'text',
-      'settings' => array(
-        'max_length' => 255,
-      )
-    );
-    field_create_field($field);
-    $instance = array(
-      'field_name' => $field['field_name'],
-      'entity_type' => 'file',
-      'bundle' => 'image',
-      'widget' => array(
-        'type' => 'text_textfield',
-      ),
-      'display' => array(
-        'default' => array(
-          'type' => 'text_default',
-        ),
-      ),
-    );
-    field_create_instance($instance);
-
-    // Create a user with file creation access.
-    $user = $this->drupalCreateUser(array('create files'));
-    $this->drupalLogin($user);
-
-    // Step 1: Upload file
-    $file = reset($this->files['image']);
-    $edit = array();
-    $edit['files[upload]'] = drupal_realpath($file->uri);
-    $this->drupalPost('file/add', $edit, t('Next'));
-
-    // Step 2: Scheme selection
-    if ($this->xpath('//input[@name="scheme"]')) {
-      $this->drupalPost(NULL, array(), t('Next'));
-    }
-
-    // Step 3: Complete field widgets
-    $langcode = LANGUAGE_NONE;
-    $edit = array();
-    $edit["{$field['field_name']}[$langcode][0][value]"] = $this->randomName();
-    $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Image', '%name' => $file->filename)), t('Image file uploaded.'));
-    $this->assertText($field['field_name'], 'File text field was found.');
-  }
-
   /**
    * Test file types CRUD UI.
    */
@@ -1067,6 +1248,9 @@ class FileEntityTypeTestCase extends FileEntityTestHelper {
   }
 }
 
+/**
+ * Tests the file entity access API.
+ */
 class FileEntityAccessTestCase extends FileEntityTestHelper {
 
   public static function getInfo() {
@@ -1079,33 +1263,20 @@ class FileEntityAccessTestCase extends FileEntityTestHelper {
 
   function setUp() {
     parent::setUp();
-    $this->setUpFiles(array('uid' => 0));
 
-    // Unset the fact that file_entity_install() adds the 'view files'
-    // permission to all user roles. This messes with being able to fully unit
-    // test the file_entity_access() function.
+    // Remove the "view files" permission which is set by default for all users
+    // so we can test this permission correctly.
     $roles = user_roles();
     foreach ($roles as $rid => $role) {
       user_role_revoke_permissions($rid, array('view files'));
     }
   }
 
-  /**
-   * Asserts file_entity_access correctly grants or denies access.
-   */
-  function assertFileEntityAccess($ops, $file, $account) {
-    drupal_static_reset('file_entity_access');
-    foreach ($ops as $op => $result) {
-      $msg = t("file_entity_access returns @result with operation '@op'.", array('@result' => $result ? 'true' : 'false', '@op' => $op));
-      $this->assertEqual($result, file_entity_access($op, $file, $account), $msg);
-    }
-  }
-
   /**
    * Runs basic tests for file_entity_access function.
    */
   function testFileEntityAccess() {
-    $file = reset($this->files['image']);
+    $file = $this->createFileEntity(array('type' => 'image'));
 
     // Ensures user with 'bypass file access' permission can do everything.
     $web_user = $this->drupalCreateUser(array('bypass file access'));
@@ -1164,70 +1335,165 @@ class FileEntityAccessTestCase extends FileEntityTestHelper {
   }
 
   /**
-   * Test to see if we have access to view files when granted the permissions.
-   * In this test we aim to prove the permissions work in the following pages:
+   * Tests page access.
+   *
+   * Verifies the privileges required to access the following pages:
    *  file/add
    *  file/%/view
    *  file/%/download
    *  file/%/edit
+   *  file/%/usage
    *  file/%/delete
    */
   function testFileEntityPageAccess() {
-    $web_user = $this->drupalCreateUser(array());
+    // Test creating files without permission.
+    $web_user = $this->drupalCreateUser();
     $this->drupalLogin($web_user);
     $this->drupalGet('file/add');
     $this->assertResponse(403, 'Users without access can not access the file add page');
-    $web_user = $this->drupalCreateUser(array('create files'));
-    $this->drupalLogin($web_user);
+
+    // Test creating files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'create files' => TRUE,
+    ));
     $this->drupalGet('file/add');
     $this->assertResponse(200, 'Users with access can access the file add page');
 
-    $file = reset($this->files['text']);
+    $file = $this->createFileEntity(array('type' => 'document','uid' => $web_user->uid));
 
-    // This fails.. No clue why but, tested manually and works as should.
-    //$web_user = $this->drupalCreateUser(array('view own files'));
-    //$this->drupalLogin($web_user);
-    //$this->drupalGet("file/{$file->fid}/view");
-    //$this->assertResponse(403, 'Users without access can not access the file view page');
-    $web_user = $this->drupalCreateUser(array('view files'));
-    $this->drupalLogin($web_user);
+    // Test viewing own files without permission.
+    $this->drupalGet("file/{$file->fid}/view");
+    $this->assertResponse(403, 'Users without access can not view their own files');
+
+    // Test viewing own files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'view own files' => TRUE,
+    ));
+    $this->drupalGet("file/{$file->fid}/view");
+    $this->assertResponse(200, 'Users with access can view their own files');
+
+    // Test viewing any files without permission.
+    $file->uid = 1;
+    file_save($file);
+    $this->drupalGet("file/{$file->fid}/view");
+    $this->assertResponse(403, 'Users with access can not view any file');
+
+    // Test viewing any files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'view files' => TRUE,
+    ));
     $this->drupalGet("file/{$file->fid}/view");
-    $this->assertResponse(200, 'Users with access can access the file view page');
+    $this->assertResponse(200, 'Users with access can view any file');
 
+    // Test downloading own files without permission.
+    $file->uid = $web_user->uid;
+    file_save($file);
     $url = "file/{$file->fid}/download";
-    $web_user = $this->drupalCreateUser(array());
-    $this->drupalLogin($web_user);
     $this->drupalGet($url, array('query' => array('token' => file_entity_get_download_token($file))));
-    $this->assertResponse(403, 'Users without access can not download the file');
-    $web_user = $this->drupalCreateUser(array('download any document files'));
-    $this->drupalLogin($web_user);
+    $this->assertResponse(403, 'Users without access can not download their own files');
+
+    // Test downloading own files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'download own document files' => TRUE,
+    ));
+    $this->drupalGet($url, array('query' => array('token' => file_entity_get_download_token($file))));
+    $this->assertResponse(200, 'Users with access can download their own files');
+
+    // Test downloading any files without permission.
+    $file->uid = 1;
+    file_save($file);
+    $url = "file/{$file->fid}/download";
     $this->drupalGet($url, array('query' => array('token' => file_entity_get_download_token($file))));
-    $this->assertResponse(200, 'Users with access can download the file');
+    $this->assertResponse(403, 'Users without access can not download any file');
+
+    // Test downloading any files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'download any document files' => TRUE,
+    ));
+    $this->drupalGet($url, array('query' => array('token' => file_entity_get_download_token($file))));
+    $this->assertResponse(200, 'Users with access can download any file');
+
+    // Test downloading files with an invalid token.
     $this->drupalGet($url, array('query' => array('token' => 'invalid-token')));
-    $this->assertResponse(403, 'Cannot download file with in invalid token.');
+    $this->assertResponse(403, 'Cannot download file with an invalid token.');
+
+    // Test downloading files without a token.
     $this->drupalGet($url);
     $this->assertResponse(403, 'Cannot download file without a token.');
     variable_set('file_entity_allow_insecure_download', TRUE);
+
+    // Test downloading files with permission but without a token when insecure
+    // downloads are enabled.
     $this->drupalGet($url);
     $this->assertResponse(200, 'Users with access can download the file without a token when file_entity_allow_insecure_download is set.');
 
-    $web_user = $this->drupalCreateUser(array());
-    $this->drupalLogin($web_user);
+    // Tests editing own files without permission.
+    $file->uid = $web_user->uid;
+    file_save($file);
     $this->drupalGet("file/{$file->fid}/edit");
-    $this->assertResponse(403, 'Users without access can not access the file edit page');
-    $web_user = $this->drupalCreateUser(array('edit any document files'));
-    $this->drupalLogin($web_user);
+    $this->assertResponse(403, 'Users without access can not edit own files');
+
+    // Tests checking the usage of their own files without permission.
+    $this->drupalGet("file/{$file->fid}/usage");
+    $this->assertResponse(403, 'Users without access can not check the usage of their own files');
+
+    // Tests editing own files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'edit own document files' => TRUE,
+    ));
     $this->drupalGet("file/{$file->fid}/edit");
-    $this->assertResponse(200, 'Users with access can access the file add page');
+    $this->assertResponse(200, 'Users with access can edit own files');
 
-    $web_user = $this->drupalCreateUser(array());
-    $this->drupalLogin($web_user);
+    // Tests checking the usage of their own files without permission.
+    $this->drupalGet("file/{$file->fid}/usage");
+    $this->assertResponse(200, 'Users with access can check the usage of their own files');
+
+    // Tests editing any files without permission.
+    $file->uid = 1;
+    file_save($file);
+    $this->drupalGet("file/{$file->fid}/edit");
+    $this->assertResponse(403, 'Users without access can not edit any file');
+
+    // Tests checking the usage of any files without permission.
+    $this->drupalGet("file/{$file->fid}/usage");
+    $this->assertResponse(403, 'Users without access can not check the usage of any file');
+
+    // Tests editing any files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'edit any document files' => TRUE,
+    ));
+    $this->drupalGet("file/{$file->fid}/edit");
+    $this->assertResponse(200, 'Users with access can edit any file');
+
+    // Tests checking the usage of any files with permission.
+    $this->drupalGet("file/{$file->fid}/usage");
+    $this->assertResponse(200, 'Users with access can check the usage of any file');
+
+    // Tests deleting own files without permission.
+    $file->uid = $web_user->uid;
+    file_save($file);
     $this->drupalGet("file/{$file->fid}/delete");
-    $this->assertResponse(403, 'Users without access can not access the file view page');
-    $web_user = $this->drupalCreateUser(array('delete any document files'));
-    $this->drupalLogin($web_user);
+    $this->assertResponse(403, 'Users without access can not delete their own files');
+
+    // Tests deleting own files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'delete own document files' => TRUE,
+    ));
     $this->drupalGet("file/{$file->fid}/delete");
-    $this->assertResponse(200, 'Users with access can access the file add page');
+    $this->assertResponse(200, 'Users with access can delete their own files');
+
+    // Tests deleting any files without permission.
+    $file->uid = 1;
+    file_save($file);
+    $this->drupalGet("file/{$file->fid}/delete");
+    $this->assertResponse(403, 'Users without access can not delete any file');
+
+    // Tests deleting any files with permission.
+    user_role_change_permissions(DRUPAL_AUTHENTICATED_RID, array(
+      'delete any document files' => TRUE,
+    ));
+    $this->drupalGet("file/{$file->fid}/delete");
+    $this->assertResponse(200, 'Users with access can delete any file');
   }
 
   /**
@@ -1244,10 +1510,7 @@ class FileEntityAccessTestCase extends FileEntityTestHelper {
 
       // Create private, permanent files owned by this user only he's an owner.
       if (!empty($case['owner'])) {
-        $file = next($this->files['text']);
-        $file->uid = $account->uid;
-        file_save($file);
-        $file = file_move($file, 'private://');
+        $file = $this->createFileEntity(array('type' => 'document', 'uid' => $account->uid, 'scheme' => 'private'));
 
         // Check if the physical file is there.
         $arguments = array('%name' => $file->filename, '%username' => $account->name, '%uri' => $file->uri);
@@ -1266,8 +1529,71 @@ class FileEntityAccessTestCase extends FileEntityTestHelper {
       }
     }
   }
+
+  /**
+   * Asserts file_entity_access correctly grants or denies access.
+   */
+  function assertFileEntityAccess($ops, $file, $account) {
+    drupal_static_reset('file_entity_access');
+    foreach ($ops as $op => $result) {
+      $msg = t("file_entity_access returns @result with operation '@op'.", array('@result' => $result ? 'true' : 'false', '@op' => $op));
+      $this->assertEqual($result, file_entity_access($op, $file, $account), $msg);
+    }
+  }
+
+  /**
+   * Helper for testFileEntityPrivateDownloadAccess() test.
+   *
+   * Defines several cases for accesing private files.
+   *
+   * @return array
+   *   Array of associative arrays, each one having the next keys:
+   *   - "message" string with the assertion message.
+   *   - "permissions" array of permissions or NULL for anonymous user.
+   *   - "expect" expected HTTP response code.
+   *   - "owner" Optional boolean indicating if the user is a file owner.
+   */
+  function getPrivateDownloadAccessCases() {
+    return array(
+      array(
+        'message' => "File owners cannot download their own files unless they are granted the 'view own private files' permission.",
+        'permissions' => array(),
+        'expect' => 403,
+        'owner' => TRUE,
+      ),
+      array(
+        'message' => "File owners can download their own files as they have been granted the 'view own private files' permission.",
+        'permissions' => array('view own private files'),
+        'expect' => 200,
+        'owner' => TRUE,
+      ),
+      array(
+        'message' => "Anonymous users cannot download private files.",
+        'permissions' => NULL,
+        'expect' => 403,
+      ),
+      array(
+        'message' => "Authenticated users cannot download each other's private files.",
+        'permissions' => array(),
+        'expect' => 403,
+      ),
+      array(
+        'message' => "Users who can view public files are not able to download private files.",
+        'permissions' => array('view files'),
+        'expect' => 403,
+      ),
+      array(
+        'message' => "Users who bypass file access can download any file.",
+        'permissions' => array('bypass file access'),
+        'expect' => 200,
+      ),
+    );
+  }
 }
 
+/**
+ * Tests overriding file attributes.
+ */
 class FileEntityAttributeOverrideTestCase extends FileEntityTestHelper {
 
   public static function getInfo() {
@@ -1278,11 +1604,6 @@ class FileEntityAttributeOverrideTestCase extends FileEntityTestHelper {
     );
   }
 
-  function setUp() {
-    parent::setUp();
-    $this->setUpFiles();
-  }
-
   /**
    * Test to see if file attributes can be overridden.
    */
@@ -1295,19 +1616,20 @@ class FileEntityAttributeOverrideTestCase extends FileEntityTestHelper {
 
     );
 
-    // Retrieve an image file entity for testing.
-    $file = reset($this->files['image']);
+    // Create an image file entity for testing.
+    $file = $this->createFileEntity(array('type' => 'image'));
 
     // Override a variety of attributes.
     foreach ($overrides as $override => $value) {
       $file->override['attributes'][$override] = $value;
     }
 
-    // Test that the attributes have been overridden.
+    // Build just the file portion of a file entity.
     $build = file_view_file($file, 'full');
 
+    // Verify that all of the overrides replaced the attributes.
     foreach ($overrides as $attribute => $expected_value) {
-      $this->assertEqual($build['#item'][$attribute], $expected_value, format_string('The %attribute was overridden correctly.', array('%attribute' => $attribute)));
+      $this->assertEqual($build['#file']->$attribute, $expected_value, format_string('The %attribute was overridden correctly.', array('%attribute' => $attribute)));
     }
   }
 }
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.theme.inc b/drupal7/sites/all/modules/file_entity/file_entity.theme.inc
index 1819d979..6801b2d8 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.theme.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.theme.inc
@@ -96,6 +96,9 @@ function theme_file_entity_file_audio($variables) {
   if ($variables['loop']) {
     $audio_attributes['loop'] = 'loop';
   }
+  if (!empty($variables['preload'])) {
+    $audio_attributes['preload'] = $variables['preload'];
+  }
 
   $output .= '<audio' . drupal_attributes($audio_attributes) . '>';
   foreach ($files as $delta => $file) {
@@ -148,6 +151,9 @@ function theme_file_entity_file_video($variables) {
   if ($variables['height']) {
     $video_attributes['height'] = $variables['height'];
   }
+  if (!empty($variables['preload'])) {
+    $video_attributes['preload'] = $variables['preload'];
+  }
 
   $output .= '<video' . drupal_attributes($video_attributes) . '>';
   foreach ($files as $delta => $file) {
diff --git a/drupal7/sites/all/modules/file_entity/file_entity.views.inc b/drupal7/sites/all/modules/file_entity/file_entity.views.inc
index 6a37901d..101123a0 100644
--- a/drupal7/sites/all/modules/file_entity/file_entity.views.inc
+++ b/drupal7/sites/all/modules/file_entity/file_entity.views.inc
@@ -162,3 +162,13 @@ function file_entity_views_plugins() {
     ),
   );
 }
+
+/**
+ * Implements hook_views_query_substitutions().
+ */
+function file_entity_views_query_substitutions() {
+  return array(
+    '***ADMINISTER_FILES***' => intval(user_access('administer files')),
+    '***BYPASS_FILE_ACCESS***' =>  intval(user_access('bypass file access')),
+  );
+}
diff --git a/drupal7/sites/all/modules/file_entity/plugins/entity/PanelizerEntityFile.class.php b/drupal7/sites/all/modules/file_entity/plugins/entity/PanelizerEntityFile.class.php
new file mode 100644
index 00000000..7f15dfbc
--- /dev/null
+++ b/drupal7/sites/all/modules/file_entity/plugins/entity/PanelizerEntityFile.class.php
@@ -0,0 +1,123 @@
+<?php
+/**
+ * @file
+ * Class for the Panelizer file entity plugin.
+ */
+
+/**
+ * Panelizer Entity file plugin class.
+ *
+ * Handles file specific functionality for Panelizer.
+ */
+class PanelizerEntityFile extends PanelizerEntityDefault {
+  public $entity_admin_root = 'admin/structure/file-types/%';
+  public $entity_admin_bundle = 3;
+  public $views_table = 'file_managed';
+
+  public function entity_access($op, $entity) {
+    return file_entity_access($op, $entity);
+  }
+
+  /**
+   * Implement the save function for the entity.
+   */
+  public function entity_save($entity) {
+    file_save($entity);
+  }
+
+  /**
+   * Implement the save function for the entity.
+   */
+  public function entity_allows_revisions($entity) {
+    return array(FALSE, FALSE);
+
+  }
+
+  public function settings_form(&$form, &$form_state) {
+    parent::settings_form($form, $form_state);
+
+    $warn = FALSE;
+    foreach ($this->plugin['bundles'] as $info) {
+      if (!empty($info['status'])) {
+        $warn = TRUE;
+        break;
+      }
+    }
+
+    if ($warn) {
+      $task = page_manager_get_task('file_view');
+      if (!empty($task['disabled'])) {
+        drupal_set_message('The file template page is currently not enabled in page manager. You must enable this for Panelizer to be able to panelize files.', 'warning');
+      }
+
+      $handler = page_manager_load_task_handler($task, '', 'file_view_panelizer');
+      if (!empty($handler->disabled)) {
+        drupal_set_message('The panelizer variant on the file template page is currently not enabled in page manager. You must enable this for Panelizer to be able to panelize files.', 'warning');
+      }
+    }
+  }
+
+  public function entity_identifier($entity) {
+    return t('This file');
+  }
+
+  public function entity_bundle_label() {
+    return t('File type');
+  }
+
+  function get_default_display($bundle, $view_mode) {
+    // For now we just go with the empty display.
+    // @todo come up with a better default display.
+    return parent::get_default_display($bundle, $view_mode);
+  }
+
+  /**
+   * Implements a delegated hook_page_manager_handlers().
+   *
+   * This makes sure that all panelized entities have the proper entry
+   * in page manager for rendering.
+   */
+  public function hook_default_page_manager_handlers(&$handlers) {
+    page_manager_get_task('file_view');
+
+    $handler = new stdClass;
+    $handler->disabled = FALSE; /* Edit this to true to make a default handler disabled initially */
+    $handler->api_version = 1;
+    $handler->name = 'file_view_panelizer';
+    $handler->task = 'file_view';
+    $handler->subtask = '';
+    $handler->handler = 'panelizer_node';
+    $handler->weight = -100;
+    $handler->conf = array(
+      'title' => t('File panelizer'),
+      'context' => 'argument_entity_id:file_1',
+      'access' => array(),
+    );
+    $handlers['file_view_panelizer'] = $handler;
+
+    return $handlers;
+  }
+
+  /**
+   * Implements a delegated hook_form_alter.
+   *
+   * We want to add Panelizer settings for the bundle to the file type form.
+   */
+  public function hook_form_alter(&$form, &$form_state, $form_id) {
+    if ($form_id == 'file_entity_file_type_form') {
+      if (isset($form['#file_type'])) {
+        $bundle = $form['#file_type']->type;
+        $this->add_bundle_setting_form($form, $form_state, $bundle, array('machine_name'));
+      }
+    }
+  }
+
+  public function hook_page_alter(&$page) {
+
+  }
+
+  public function hook_views_plugins_alter(&$plugins) {
+
+  }
+
+}
diff --git a/drupal7/sites/all/modules/file_entity/plugins/entity/file.inc b/drupal7/sites/all/modules/file_entity/plugins/entity/file.inc
new file mode 100644
index 00000000..fd582311
--- /dev/null
+++ b/drupal7/sites/all/modules/file_entity/plugins/entity/file.inc
@@ -0,0 +1,22 @@
+<?php
+/**
+ * @file
+ * Definition of the Panelizer file plugin.
+ */
+
+$plugin = array(
+  'handler' => 'PanelizerEntityFile',
+  'entity path' => 'file/%file',
+  'uses page manager' => TRUE,
+  'hooks' => array(
+    'menu' => TRUE,
+    'admin_paths' => TRUE,
+    'permission' => TRUE,
+    'panelizer_defaults' => TRUE,
+    'default_page_manager_handlers' => TRUE,
+    'form_alter' => TRUE,
+    'page_alter' => TRUE,
+    'views_data_alter' => TRUE,
+    'views_plugins_alter' => TRUE,
+  ),
+);
diff --git a/drupal7/sites/all/modules/file_entity/plugins/tasks/file_view.inc b/drupal7/sites/all/modules/file_entity/plugins/tasks/file_view.inc
new file mode 100644
index 00000000..5b823758
--- /dev/null
+++ b/drupal7/sites/all/modules/file_entity/plugins/tasks/file_view.inc
@@ -0,0 +1,164 @@
+<?php
+
+/**
+ * @file
+ * Handle the 'file view' override task.
+ *
+ * This plugin overrides file/%file and reroutes it to the page manager, where
+ * a list of tasks can be used to service this request based upon criteria
+ * supplied by access plugins.
+ */
+
+/**
+ * Specialized implementation of hook_page_manager_task_tasks().
+ */
+function file_entity_file_view_page_manager_tasks() {
+  return array(
+    // This is a 'page' task and will fall under the page admin UI
+    'task type' => 'page',
+    'title' => t('File template'),
+    'admin title' => t('File template'),
+    'admin description' => t('When enabled, this overrides the default Drupal behavior for displaying files at <em>file/%file</em>. If you add variants, you may use selection criteria such as file types or user access to provide different views of files. If no variant is selected, the default Drupal file view will be used. This page only affects files viewed as pages, it will not affect files viewed in lists or at other locations. Also please note that if you are using Pathauto, aliases may make a file to be available somewhere else, but as far as Drupal is concerned, they are still at file/%file.'),
+    'admin path' => 'file/%file',
+
+    // Menu hooks so that we can alter the file/%file menu entry to point to us.
+    'hook menu' => 'file_entity_file_view_menu',
+    'hook menu alter' => 'file_entity_file_view_menu_alter',
+
+    // This is task uses 'context' handlers and must implement these to give the
+    // handler data it needs.
+    'handler type' => 'context',
+    'get arguments' => 'file_entity_file_view_get_arguments',
+    'get context placeholders' => 'file_entity_file_view_get_contexts',
+
+    // Allow this to be enabled or disabled:
+    'disabled' => variable_get('file_entity_file_view_disabled', TRUE),
+    'enable callback' => 'file_entity_file_view_enable',
+    'access callback' => 'file_entity_file_view_access_check',
+  );
+}
+
+/**
+ * Callback defined by page_manager_file_view_page_manager_tasks().
+ *
+ * Alter the file view input so that file view comes to us rather than the
+ * normal file view process.
+ */
+function file_entity_file_view_menu_alter(&$items, $task) {
+  if (variable_get('file_entity_file_view_disabled', TRUE)) {
+    return;
+  }
+
+  // Override the node view handler for our purpose.
+  $callback = $items['file/%file']['page callback'];
+  if ($callback == 'file_entity_view_page' || variable_get('page_manager_override_anyway', FALSE)) {
+    $items['file/%file']['page callback'] = 'file_entity_file_view_page';
+    $items['file/%file']['file path'] = $task['path'];
+    $items['file/%file']['file'] = $task['file'];
+  }
+  else {
+    // automatically disable this task if it cannot be enabled.
+    variable_set('file_entity_file_view_disabled', TRUE);
+    if (!empty($GLOBALS['page_manager_enabling_file_view'])) {
+      drupal_set_message(t('Page manager module is unable to enable file/%file because some other module already has overridden with %callback.', array('%callback' => $callback)), 'error');
+    }
+  }
+}
+
+/**
+ * Entry point for our overridden file view.
+ *
+ * This function asks its assigned handlers who, if anyone, would like
+ * to run with it. If no one does, it passes through to File entity's
+ * file view, which is file_entity_view_page().
+ */
+function file_entity_file_view_page($file) {
+  // Load my task plugin:
+  $task = page_manager_get_task('file_view');
+
+  // Load the account into a context.
+  ctools_include('context');
+  ctools_include('context-task-handler');
+  $contexts = ctools_context_handler_get_task_contexts($task, '', array($file));
+
+  // We need to mimic Drupal's behavior of setting the file title here.
+  drupal_set_title($file->filename);
+  $uri = entity_uri('file', $file);
+  // Set the file path as the canonical URL to prevent duplicate content.
+  drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
+  // Set the non-aliased path as a default shortlink.
+  drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);
+  $contexts = ctools_context_handler_get_task_contexts($task, '', array($file));
+
+  $output = ctools_context_handler_render($task, '', $contexts, array($file->fid));
+  if ($output != FALSE) {
+    return $output;
+  }
+
+  $function = 'file_entity_view_page';
+  foreach (module_implements('page_manager_override') as $module) {
+    $call = $module . '_page_manager_override';
+    if (($rc = $call('file_view')) && function_exists($rc)) {
+      $function = $rc;
+      break;
+    }
+  }
+
+  // Otherwise, fall back.
+  return $function($file);
+}
+
+/**
+ * Callback to get arguments provided by this task handler.
+ *
+ * Since this is the file view and there is no UI on the arguments, we
+ * create dummy arguments that contain the needed data.
+ */
+function file_entity_file_view_get_arguments($task, $subtask_id) {
+  return array(
+    array(
+      'keyword' => 'file',
+      'identifier' => t('File being viewed'),
+      'id' => 1,
+      'name' => 'entity_id:file',
+      'settings' => array(),
+    ),
+  );
+}
+
+/**
+ * Callback to get context placeholders provided by this handler.
+ */
+function file_entity_file_view_get_contexts($task, $subtask_id) {
+  return ctools_context_get_placeholders_from_argument(page_manager_file_view_get_arguments($task, $subtask_id));
+}
+
+/**
+ * Callback to enable/disable the page from the UI.
+ */
+function file_entity_file_view_enable($cache, $status) {
+  variable_set('file_entity_file_view_disabled', $status);
+
+  // Set a global flag so that the menu routine knows it needs
+  // to set a message if enabling cannot be done.
+  if (!$status) {
+    $GLOBALS['page_manager_enabling_file_view'] = TRUE;
+  }
+}
+
+/**
+ * Callback to determine if a page is accessible.
+ *
+ * @param $task
+ *   The task plugin.
+ * @param $subtask_id
+ *   The subtask id
+ * @param $contexts
+ *   The contexts loaded for the task.
+ * @return
+ *   TRUE if the current user can access the page.
+ */
+function page_manager_file_view_access_check($task, $subtask_id, $contexts) {
+  $context = reset($contexts);
+  return file_entity_access('view');
+}
diff --git a/drupal7/sites/all/modules/file_entity/tests/file_entity_test.info b/drupal7/sites/all/modules/file_entity/tests/file_entity_test.info
index cf354022..fd1bbc93 100644
--- a/drupal7/sites/all/modules/file_entity/tests/file_entity_test.info
+++ b/drupal7/sites/all/modules/file_entity/tests/file_entity_test.info
@@ -5,9 +5,9 @@ core = 7.x
 dependencies[] = file_entity
 hidden = TRUE
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-beta1"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta2"
 core = "7.x"
 project = "file_entity"
-datestamp = "1412420930"
+datestamp = "1436896443"
 
diff --git a/drupal7/sites/all/modules/media/includes/media.browser.inc b/drupal7/sites/all/modules/media/includes/media.browser.inc
index d8037221..d5285f0a 100644
--- a/drupal7/sites/all/modules/media/includes/media.browser.inc
+++ b/drupal7/sites/all/modules/media/includes/media.browser.inc
@@ -24,7 +24,8 @@ function media_browser($selected = NULL) {
     }
     $files = file_load_multiple($fids);
     foreach ($files as $file) {
-      media_browser_build_media_item($file);
+      $view_mode = isset($params['view_mode']) ? $params['view_mode'] : 'preview';
+      media_browser_build_media_item($file, $view_mode);
     }
     $setting = array('media' => array('selectedMedia' => array_values($files)));
     drupal_add_js($setting, 'setting');
@@ -148,71 +149,12 @@ function media_browser($selected = NULL) {
   return $output;
 }
 
-/**
- * Attaches media browser javascript to an element.
- *
- * @param array $element
- *   The element array to attach to.
- */
-function media_attach_browser_js(&$element) {
-  $javascript = media_browser_js();
-  foreach ($javascript as $key => $definitions) {
-    foreach ($definitions as $definition) {
-      $element['#attached'][$key][] = $definition;
-    }
-  }
-}
-
-/**
- * Helper function to define browser javascript.
- */
-function media_browser_js() {
-  $settings = array(
-    'browserUrl' => url('media/browser', array(
-      'query' => array(
-        'render' => 'media-popup'
-      ))
-    ),
-    'styleSelectorUrl' => url('media/-media_id-/format-form', array(
-      'query' => array(
-        'render' => 'media-popup'
-      ))
-    ),
-    'dialogOptions' => array(
-      'dialogclass' => variable_get('media_dialogclass', 'media-wrapper'),
-      'modal' => (boolean)variable_get('media_modal', TRUE),
-      'draggable' => (boolean)variable_get('media_draggable', FALSE),
-      'resizable' => (boolean)variable_get('media_resizable', FALSE),
-      'minwidth' => (int)variable_get('media_minwidth', 500),
-      'width' => (int)variable_get('media_width', 670),
-      'height' => (int)variable_get('media_height', 280),
-      'position' => variable_get('media_position', 'center'),
-      'overlay' => array(
-        'backgroundcolor' => variable_get('media_backgroundcolor', '#000000'),
-        'opacity' => (float)variable_get('media_opacity', 0.4),
-      ),
-      'zindex' => (int)variable_get('media_zindex', 10000),
-    ),
-  );
-
-  return array(
-    'library' => array(
-      array('media', 'media_browser'),
-    ),
-    'js' => array(
-      array(
-       'data' => array('media' => $settings),
-       'type' => 'setting',
-      ),
-    ),
-  );
-}
-
 /**
  * Menu callback for testing the media browser.
  */
 function media_browser_testbed($form) {
-  media_attach_browser_js($form);
+  $form['#attached']['library'][] = array('media', 'media_browser');
+  $form['#attached']['library'][] = array('media', 'media_browser_settings');
 
   $form['test_element'] = array(
     '#type' => 'media',
@@ -290,12 +232,13 @@ EOF;
 }
 
 /**
- * Adds properties to the file.
+ * Adds additional properties to a file which are needed by the browser JS code.
  *
- * Additional properties on this file are needed by the media browser JS code.
+ * @param object $file
+ *   A Drupal file object.
  */
-function media_browser_build_media_item($file) {
-  $preview = media_get_thumbnail_preview($file);
+function media_browser_build_media_item($file, $view_mode = 'preview') {
+  $preview = media_get_thumbnail_preview($file, NULL, $view_mode);
   $file->preview = drupal_render($preview);
   $file->url = file_create_url($file->uri);
 }
diff --git a/drupal7/sites/all/modules/media/includes/media.fields.inc b/drupal7/sites/all/modules/media/includes/media.fields.inc
index c3132116..0820fc16 100644
--- a/drupal7/sites/all/modules/media/includes/media.fields.inc
+++ b/drupal7/sites/all/modules/media/includes/media.fields.inc
@@ -15,9 +15,13 @@ function media_field_widget_info() {
       'label' => t('Media browser'),
       'field types' => array('file', 'image'),
       'settings' => array(
-        'allowed_types' => array('image'),
+        'allowed_types' => array(
+          'image' => 'image',
+        ),
         'browser_plugins' => array(),
-        'allowed_schemes' => array('public', 'private'),
+        'allowed_schemes' => array(
+          'public' => 'public',
+        ),
       ),
       'behaviors' => array(
         'multiple values' => FIELD_BEHAVIOR_CUSTOM,
@@ -77,12 +81,6 @@ function media_field_widget_settings_form($field, $instance) {
  * Implements hook_field_widget_form().
  */
 function media_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
-
-  // Add display_field setting to field because media_field_widget_form() assumes it is set.
-  if (!isset($field['settings']['display_field'])) {
-    $field['settings']['display_field'] = 0;
-  }
-
   $defaults = array(
     'fid' => 0,
     'display' => !empty($field['settings']['display_default']),
@@ -164,7 +162,7 @@ function media_field_widget_form(&$form, &$form_state, $field, $instance, $langc
     $elements['#description'] = $element['#description'];
     $elements['#field_name'] = $element['#field_name'];
     $elements['#language'] = $element['#language'];
-    $elements['#display_field'] = $field['settings']['display_field'];
+    $elements['#display_field'] = intval(!empty($field['settings']['display_field']));
 
     // Add some properties that will eventually be added to the media upload
     // field. These are added here so that they may be referenced easily through
@@ -185,7 +183,7 @@ function media_field_widget_value($element, $input = FALSE, $form_state) {
     // If the display field is present make sure its unchecked value is saved.
     $field = field_widget_field($element, $form_state);
     if (empty($input['display'])) {
-      $input['display'] = $field['settings']['display_field'] ? 0 : 1;
+      $input['display'] = intval(!empty($field['settings']['display_field']));
     }
   }
 
@@ -450,7 +448,7 @@ function theme_media_widget_multiple($variables) {
     // "operations" column.
     $operations_elements = array();
     foreach (element_children($widget) as $sub_key) {
-      if (isset($widget[$sub_key]['#type']) && $widget[$sub_key]['#type'] == 'submit') {
+      if (isset($widget[$sub_key]['#type']) && ($widget[$sub_key]['#type'] == 'submit' || $widget[$sub_key]['#type'] == 'link')) {
         hide($widget[$sub_key]);
         $operations_elements[] = &$widget[$sub_key];
       }
@@ -543,11 +541,64 @@ function media_field_formatter_info() {
     'media_large_icon' => array(
       'label' => t('Large filetype icon'),
       'field types' => array('file'),
+      'settings' => array(
+        'image_style' => '',
+      ),
     ),
   );
+
   return $formatters;
 }
 
+/**
+ * Implements hook_field_formatter_settings_form().
+ *
+ * Legacy support for the "Large filetype icon" file field formatter.
+ * @see media_field_formatter_info()
+ */
+function media_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $image_styles = image_style_options(FALSE, PASS_THROUGH);
+  $element['image_style'] = array(
+    '#title' => t('Image style'),
+    '#type' => 'select',
+    '#default_value' => $settings['image_style'],
+    '#empty_option' => t('None (original image)'),
+    '#options' => $image_styles,
+  );
+
+  return $element;
+}
+
+/**
+ * Implements hook_field_formatter_settings_summary().
+ *
+ * Legacy support for the "Large filetype icon" file field formatter.
+ * @see media_field_formatter_info()
+ */
+function media_field_formatter_settings_summary($field, $instance, $view_mode) {
+  $display = $instance['display'][$view_mode];
+  $settings = $display['settings'];
+
+  $summary = array();
+
+  $image_styles = image_style_options(FALSE, PASS_THROUGH);
+  // Unset possible 'No defined styles' option.
+  unset($image_styles['']);
+  // Styles could be lost because of enabled/disabled modules that defines
+  // their styles in code.
+  if (isset($image_styles[$settings['image_style']])) {
+    $summary[] = t('Image style: @style', array('@style' => $image_styles[$settings['image_style']]));
+  }
+  else {
+    $summary[] = t('Original image');
+  }
+
+  return implode('<br />', $summary);
+}
+
 /**
  * Implements hook_field_formatter_view().
  *
@@ -558,12 +609,11 @@ function media_field_formatter_view($entity_type, $entity, $field, $instance, $l
   $element = array();
 
   if ($display['type'] == 'media_large_icon') {
-    // Use the media_thumbnail image style so that the output in media browser
-    // is consistent.
     foreach ($items as $delta => $item) {
       $element[$delta] = array(
         '#theme' => 'media_formatter_large_icon',
         '#file' => (object) $item,
+        '#style_name' => $display['settings']['image_style'],
       );
     }
   }
diff --git a/drupal7/sites/all/modules/media/js/media.browser.js b/drupal7/sites/all/modules/media/js/media.browser.js
index d16e52aa..88490e59 100644
--- a/drupal7/sites/all/modules/media/js/media.browser.js
+++ b/drupal7/sites/all/modules/media/js/media.browser.js
@@ -30,7 +30,7 @@ Drupal.behaviors.MediaBrowser = {
       }
     };
     var activeTab = Drupal.media.browser.tabFromHash();
-    $('#media-browser-tabset').tabs({
+    $('#media-browser-tabset').once('MediaBrowser').tabs({
       selected: activeTab, // jquery < 1.9
       active: activeTab, // jquery >= 1.9
       show: showFunc, // jquery ui < 1.8
@@ -107,6 +107,11 @@ Drupal.media.browser.selectMedia = function (selectedMedia) {
   Drupal.media.browser.selectedMedia = selectedMedia;
 };
 
+Drupal.media.browser.selectMediaAndSubmit = function (selectedMedia) {
+  Drupal.media.browser.selectedMedia = selectedMedia;
+  Drupal.media.browser.submit();
+};
+
 Drupal.media.browser.finalizeSelection = function () {
   if (!Drupal.media.browser.selectedMedia) {
     throw new exception(Drupal.t('Cannot continue, nothing selected'));
diff --git a/drupal7/sites/all/modules/media/js/plugins/media.views.js b/drupal7/sites/all/modules/media/js/plugins/media.views.js
index b5024b39..455288d6 100644
--- a/drupal7/sites/all/modules/media/js/plugins/media.views.js
+++ b/drupal7/sites/all/modules/media/js/plugins/media.views.js
@@ -80,6 +80,36 @@ Drupal.media.browser.views.setup = function(view) {
   // Reset the list of selected files
   Drupal.media.browser.selectMedia([]);
 
+  // Catch double click to submit a single item.
+  $('.view-content .media-item', view).bind('dblclick', function () {
+    var fid = $(this).closest('.media-item[data-fid]').data('fid'),
+      selectedFiles = new Array();
+
+    // Remove all currently selected files
+    $('.view-content .media-item', view).removeClass('selected');
+
+    // Mark it as selected
+    $(this).addClass('selected');
+
+    // Because the files are added using drupal_add_js() and due to the fact
+    // that drupal_get_js() runs a drupal_array_merge_deep() which re-numbers
+    // numeric key values, we have to search in Drupal.settings.media.files
+    // for the matching file ID rather than referencing it directly.
+    for (index in Drupal.settings.media.files) {
+      if (Drupal.settings.media.files[index].fid == fid) {
+        selectedFiles.push(Drupal.settings.media.files[index]);
+
+        // If multiple tabs contains the same file, it will be present in the
+        // files-array multiple times, so we break out early so we don't have
+        // it in the selectedFiles array multiple times.
+        // This would interfer with multi-selection, so...
+        break;
+      }
+    }
+    Drupal.media.browser.selectMediaAndSubmit(selectedFiles);
+  });
+
+
   // Catch the click on a media item
   $('.view-content .media-item', view).bind('click', function () {
     var fid = $(this).closest('.media-item[data-fid]').data('fid'),
diff --git a/drupal7/sites/all/modules/media/media.api.php b/drupal7/sites/all/modules/media/media.api.php
index 4ff1c4f8..ecde61b2 100644
--- a/drupal7/sites/all/modules/media/media.api.php
+++ b/drupal7/sites/all/modules/media/media.api.php
@@ -14,6 +14,7 @@
  * @return array
  *   The unique URI for the file, based on its stream wrapper, or NULL.
  *
+ * @see hook_media_parse_alter()
  * @see media_parse_to_file()
  * @see media_add_from_url_validate()
  */
@@ -27,6 +28,37 @@ function hook_media_parse($url) {
   }
 }
 
+/**
+ * Alters the parsing of urls and embedded codes into unique URIs.
+ *
+ * @param string $success
+ *   The unique URI for the file, based on its stream wrapper, or NULL.
+ * @param array $context
+ *   A nested array of contextual information containing the following keys:
+ *   - url: The original URL or embed code to parse.
+ *   - module: The name of the module which is attempting to parse the url or
+ *     embedded code into a unique URI.
+ *
+ * @see hook_media_parse()
+ * @see hook_media_browser_plugin_info()
+ * @see media_get_browser_plugin_info()
+ */
+function hook_media_parse_alter(&$success, $context) {
+  $url = $context['url'];
+  $url_info = parse_url($url);
+
+  // Restrict users to only embedding secure links.
+  if ($url_info['scheme'] != 'https') {
+    $success = NULL;
+  }
+
+  // Use a custom handler for detecting YouTube videos.
+  if ($context['module' == 'media_youtube']) {
+    $handler = new CustomYouTubeHandler($url);
+    $success = $handler->parse($url);
+  }
+}
+
 /**
  * Returns a list of plugins for the media browser.
  *
@@ -99,6 +131,7 @@ function hook_media_browser_plugins_alter(&$plugin_output) {
  * @see media_set_browser_params()
  */
 function hook_media_browser_params_alter(&$stored_params) {
+  $stored_params['view_mode'] = 'custom';
   $stored_params['types'][] = 'document';
   unset($stored_params['enabledPlugins'][0]);
 }
diff --git a/drupal7/sites/all/modules/media/media.file_default_displays.inc b/drupal7/sites/all/modules/media/media.file_default_displays.inc
index ec7a378f..3e3e2c13 100644
--- a/drupal7/sites/all/modules/media/media.file_default_displays.inc
+++ b/drupal7/sites/all/modules/media/media.file_default_displays.inc
@@ -15,36 +15,44 @@ function media_file_default_displays() {
   $file_display = new stdClass();
   $file_display->api_version = 1;
   $file_display->name = 'audio__preview__file_field_media_large_icon';
-  $file_display->weight = 50;
+  $file_display->weight = 49;
   $file_display->status = TRUE;
-  $file_display->settings = '';
+  $file_display->settings = array(
+    'image_style' => 'media_thumbnail',
+  );
   $file_displays['audio__preview__file_field_media_large_icon'] = $file_display;
 
   // Document previews should be displayed using a large filetype icon.
   $file_display = new stdClass();
   $file_display->api_version = 1;
   $file_display->name = 'document__preview__file_field_media_large_icon';
-  $file_display->weight = 50;
+  $file_display->weight = 49;
   $file_display->status = TRUE;
-  $file_display->settings = '';
+  $file_display->settings = array(
+    'image_style' => 'media_thumbnail',
+  );
   $file_displays['document__preview__file_field_media_large_icon'] = $file_display;
 
   // Image previews should be displayed using a large filetype icon.
   $file_display = new stdClass();
   $file_display->api_version = 1;
   $file_display->name = 'image__preview__file_field_media_large_icon';
-  $file_display->weight = 50;
+  $file_display->weight = 49;
   $file_display->status = TRUE;
-  $file_display->settings = '';
+  $file_display->settings = array(
+    'image_style' => 'media_thumbnail',
+  );
   $file_displays['image__preview__file_field_media_large_icon'] = $file_display;
 
   // Video previews should be displayed using a large filetype icon.
   $file_display = new stdClass();
   $file_display->api_version = 1;
   $file_display->name = 'video__preview__file_field_media_large_icon';
-  $file_display->weight = 50;
+  $file_display->weight = 49;
   $file_display->status = TRUE;
-  $file_display->settings = '';
+  $file_display->settings = array(
+    'image_style' => 'media_thumbnail',
+  );
   $file_displays['video__preview__file_field_media_large_icon'] = $file_display;
 
   return $file_displays;
diff --git a/drupal7/sites/all/modules/media/media.info b/drupal7/sites/all/modules/media/media.info
index 27a92be0..c7b8f871 100644
--- a/drupal7/sites/all/modules/media/media.info
+++ b/drupal7/sites/all/modules/media/media.info
@@ -24,9 +24,9 @@ configure = admin/config/media/browser
 ; We have to add a fake version so Git checkouts do not fail Media dependencies
 version = 7.x-2.x-dev
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/media.install b/drupal7/sites/all/modules/media/media.install
index 43a17456..1e7ae31d 100644
--- a/drupal7/sites/all/modules/media/media.install
+++ b/drupal7/sites/all/modules/media/media.install
@@ -104,7 +104,7 @@ function media_update_dependencies() {
 function media_requirements($phase) {
   $t = get_t();
   // Make sure that file_entity module is 2.x version.
-  // We can't add this check in .info file because drupal.org testbot cant
+  // We can't add this check in .info file because drupal.org testbot can't
   // handle it. See #1734648.
   $requirements = array();
 
@@ -139,6 +139,10 @@ function media_update_7001() {
  * Create the media_type table from the media_types variable.
  */
 function media_update_7002() {
+  if (db_table_exists('media_type')) {
+    return;
+  }
+
   $schema['media_type'] = array(
     'description' => 'Stores the settings for media types.',
     'fields' => array(
@@ -190,7 +194,7 @@ function media_update_7002() {
   db_create_table('media_type', $schema['media_type']);
 
   drupal_load('module', 'media');
-  $old_types = variable_get('media_types');
+  $old_types = variable_get('media_types', array());
   foreach ($old_types as $type) {
     // Was an error in the original creation.
     if (isset($type->callbacks)) {
@@ -496,6 +500,13 @@ function media_update_7020() {
   }
 }
 
+/**
+ * Rerun media_update_7002() due to a typo that would prevent table creation.
+ */
+function media_update_7021() {
+  media_update_7002();
+}
+
 /**
  * Replace 'view media' perm from all users having the role with 'view file'.
  */
@@ -1160,9 +1171,7 @@ function media_update_7225() {
 }
 
 /**
- * Accommodate the introduction of a new permission which restricts access to
- * the media browser by granting it to existing users who were able to access
- * it.
+ * Grant existing user access to new media browser permission.
  */
 function media_update_7226() {
   $roles = user_roles(FALSE, 'create files');
diff --git a/drupal7/sites/all/modules/media/media.module b/drupal7/sites/all/modules/media/media.module
index 3c54914a..1f97bcb7 100644
--- a/drupal7/sites/all/modules/media/media.module
+++ b/drupal7/sites/all/modules/media/media.module
@@ -358,8 +358,9 @@ function media_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
   }
 
   // Add a validation function to any field instance which uses the media widget
-  // to ensure that the upload destination scheme is one of the allowed schemes.
-  if ($form['instance']['widget']['type']['#value'] == 'media_generic') {
+  // to ensure that the upload destination scheme is one of the allowed schemes
+  // if any defined by settings.
+  if ($form['instance']['widget']['type']['#value'] == 'media_generic' && isset($form['#field']['settings']['uri_scheme'])) {
     $form['#validate'][] = 'media_field_instance_validate';
   }
 
@@ -378,10 +379,10 @@ function media_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
  * allowed schemes.
  */
 function media_field_instance_validate($form, &$form_state) {
-  $allowed_schemes = $form_state['values']['instance']['widget']['settings']['allowed_schemes'];
+  $allowed_schemes = array_filter($form_state['values']['instance']['widget']['settings']['allowed_schemes']);
   $upload_destination = $form_state['values']['field']['settings']['uri_scheme'];
 
-  if (!in_array($upload_destination, array_filter($allowed_schemes))) {
+  if (!empty($allowed_schemes) && !in_array($upload_destination, $allowed_schemes)) {
     form_set_error('allowed_schemes', t('The upload destination must be one of the allowed schemes.'));
   }
 }
@@ -393,8 +394,13 @@ function media_form_alter(&$form, &$form_state, $form_id) {
   // If we're in the media browser, set the #media_browser key to true
   // so that if an ajax request gets sent to a different path, the form
   // still uses the media_browser_form_submit callback.
-  if (current_path() == 'media/browser' && $form_id != 'views_exposed_form') {
-    $form_state['#media_browser'] = TRUE;
+  if (current_path() == 'media/browser') {
+    if ($form_id == 'views_exposed_form') {
+      $form['render'] = array('#type' => 'hidden', '#value' => 'media-popup');
+      $form['#action'] = '/media/browser';
+    } else {
+      $form_state['#media_browser'] = TRUE;
+    }
   }
 
   // If the #media_browser key isset and is true we are using the browser
@@ -478,6 +484,47 @@ function media_library() {
     ),
   );
 
+  // Settings for the dialog etc.
+  $settings = array(
+    'browserUrl' => url('media/browser', array(
+      'query' => array(
+        'render' => 'media-popup'
+      ))
+    ),
+    'styleSelectorUrl' => url('media/-media_id-/format-form', array(
+      'query' => array(
+        'render' => 'media-popup'
+      ))
+    ),
+    'dialogOptions' => array(
+      'dialogclass' => variable_get('media_dialogclass', 'media-wrapper'),
+      'modal' => (boolean)variable_get('media_modal', TRUE),
+      'draggable' => (boolean)variable_get('media_draggable', FALSE),
+      'resizable' => (boolean)variable_get('media_resizable', FALSE),
+      'minwidth' => (int)variable_get('media_minwidth', 500),
+      'width' => (int)variable_get('media_width', 670),
+      'height' => (int)variable_get('media_height', 280),
+      'position' => variable_get('media_position', 'center'),
+      'overlay' => array(
+        'backgroundcolor' => variable_get('media_backgroundcolor', '#000000'),
+        'opacity' => (float)variable_get('media_opacity', 0.4),
+      ),
+      'zindex' => (int)variable_get('media_zindex', 10000),
+    ),
+  );
+
+  $libraries['media_browser_settings'] = array(
+    'title' => 'Media browser settings',
+    'js' => array(
+      0 => array(
+        'data' => array(
+          'media' => $settings,
+        ),
+        'type' => 'setting',
+      ),
+    ),
+  );
+
   foreach ($libraries as &$library) {
     $library += $common;
   }
@@ -538,6 +585,11 @@ function media_parse_to_uri($url) {
   $url = trim($url);
   foreach (module_implements('media_parse') as $module) {
     $success = module_invoke($module, 'media_parse', $url);
+    $context = array(
+      'url' => $url,
+      'module' => $module,
+    );
+    drupal_alter('media_parse', $success, $context);
     if (isset($success)) {
       return $success;
     }
@@ -660,6 +712,11 @@ function media_element_process($element, &$form_state, $form) {
   ctools_include('modal');
   ctools_include('ajax');
   ctools_modal_add_js();
+
+  // Append the '-upload' to the #id so the field label's 'for' attribute
+  // corresponds with the textfield element.
+  $original_id = $element['#id'];
+  $element['#id'] .= '-upload';
   $fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : 0;
 
   // Set some default element properties.
@@ -668,7 +725,7 @@ function media_element_process($element, &$form_state, $form) {
 
   $ajax_settings = array(
     'path' => 'media/ajax/' . implode('/', $element['#array_parents']) . '/' . $form['form_build_id']['#value'],
-    'wrapper' => $element['#id'] . '-ajax-wrapper',
+    'wrapper' => $original_id . '-ajax-wrapper',
     'effect' => 'fade',
   );
 
@@ -769,11 +826,11 @@ function media_element_process($element, &$form_state, $form) {
     )
   );
 
-  module_load_include('inc', 'media', 'includes/media.browser');
-  media_attach_browser_js($element);
+  $element['#attached']['library'][] = array('media', 'media_browser');
+  $element['#attached']['library'][] = array('media', 'media_browser_settings');
 
   // Prefix and suffix used for Ajax replacement.
-  $element['#prefix'] = '<div id="' . $element['#id'] . '-ajax-wrapper">';
+  $element['#prefix'] = '<div id="' . $original_id . '-ajax-wrapper">';
   $element['#suffix'] = '</div>';
 
   return $element;
@@ -1015,28 +1072,35 @@ function media_element_pre_render($element) {
 }
 
 /**
- * Media thumbnail render function.
+ * Generates a thumbnail preview of a file.
  *
- * Returns a renderable array with the necessary classes to support a media
- * thumbnail. Also provides default fallback images if no image is available.
+ * Provides default fallback images if an image of the file cannot be generated.
  *
  * @param object $file
  *   A Drupal file object.
+ * @param boolean $link
+ *   (optional) Boolean indicating whether the thumbnail should be linked to the
+ *   file. Defaults to FALSE.
+ * @param string $view_mode
+ *   (optional) The view mode to use when rendering the thumbnail. Defaults to
+ *   'preview'.
  *
  * @return array
- *   Renderable array.
+ *   Renderable array suitable for drupal_render() with the necessary classes
+ *   and CSS to support a media thumbnail.
  */
-function media_get_thumbnail_preview($file, $link = NULL) {
+function media_get_thumbnail_preview($file, $link = FALSE, $view_mode = 'preview') {
   // If a file has an invalid type, allow file_view_file() to work.
   if (!file_type_is_enabled($file->type)) {
     $file->type = file_get_type($file);
   }
 
-  $preview = file_view_file($file, 'preview');
+  $preview = file_view_file($file, $view_mode);
   $preview['#show_names'] = TRUE;
   $preview['#add_link'] = $link;
   $preview['#theme_wrappers'][] = 'media_thumbnail';
   $preview['#attached']['css'][] = drupal_get_path('module', 'media') . '/css/media.css';
+
   return $preview;
 }
 
@@ -1278,6 +1342,9 @@ function media_load_all_exports($module, $directory, $extension, $name = NULL) {
 /**
  * Returns metadata describing Media browser plugins.
  *
+ * @return
+ *   An associative array of plugin information, keyed by plugin.
+ *
  * @see hook_media_browser_plugin_info()
  * @see hook_media_browser_plugin_info_alter()
  */
@@ -1285,15 +1352,8 @@ function media_get_browser_plugin_info() {
   $info = &drupal_static(__FUNCTION__);
 
   if (!isset($info)) {
-    $cid = 'media:browser:plugin:info:' . $GLOBALS['language']->language;
-    if ($cache = cache_get($cid)) {
-      $info = $cache->data;
-    }
-    else {
-      $info = module_invoke_all('media_browser_plugin_info');
-      drupal_alter('media_browser_plugin_info', $info);
-      cache_set($cid, $info);
-    }
+    $info = module_invoke_all('media_browser_plugin_info');
+    drupal_alter('media_browser_plugin_info', $info);
   }
 
   return $info;
diff --git a/drupal7/sites/all/modules/media/media.views.inc b/drupal7/sites/all/modules/media/media.views.inc
index 9d116bfc..aed55fa4 100644
--- a/drupal7/sites/all/modules/media/media.views.inc
+++ b/drupal7/sites/all/modules/media/media.views.inc
@@ -74,10 +74,13 @@ function template_preprocess_media_views_view_media_browser(&$vars) {
   $files = file_load_multiple($fids);
 
   // Render the preview for each file.
+  $params = media_get_browser_params();
+  $view_mode = isset($params['view_mode']) ? $params['view_mode'] : 'preview';
+
   foreach ($vars['rows'] as $index => $row) {
     $file = $files[$row->fid];
     // Add url/preview to the file object.
-    media_browser_build_media_item($file);
+    media_browser_build_media_item($file, $view_mode);
     $vars['rows'][$index] = $file;
     $vars['rows'][$index]->preview = $file->preview;
   }
@@ -126,6 +129,5 @@ function template_preprocess_media_views_view_media_browser(&$vars) {
  * Implements hook_views_invalidate_cache().
  */
 function media_views_invalidate_cache() {
-  cache_clear_all('media:browser:plugin', 'cache', TRUE);
   drupal_static_reset('media_get_browser_plugin_info');
 }
diff --git a/drupal7/sites/all/modules/media/modules/media_bulk_upload/includes/media_bulk_upload.pages.inc b/drupal7/sites/all/modules/media/modules/media_bulk_upload/includes/media_bulk_upload.pages.inc
index 50d0b560..41287ebb 100644
--- a/drupal7/sites/all/modules/media/modules/media_bulk_upload/includes/media_bulk_upload.pages.inc
+++ b/drupal7/sites/all/modules/media/modules/media_bulk_upload/includes/media_bulk_upload.pages.inc
@@ -27,13 +27,42 @@ function media_bulk_upload_file_page_edit_multiple($files) {
   $form = call_user_func_array('multiform_get_form', $forms);
   $form['#attributes']['class'][] = 'media-bulk-upload-multiedit-form';
 
-  // Add the title to each 'subform'.
+  // Improve the display of each file form.
   foreach (element_children($form['multiform']) as $key) {
     $fid = $form['multiform'][$key]['fid']['#value'];
     $file = $files[$fid];
+
+    // Add the filename to each 'subform'.
     $title = t('<em>Edit @type</em> @title', array('@type' => $file->type, '@title' => $file->filename));
     $form['multiform'][$key]['#prefix'] = '<h2>' . $title . '</h2>';
+
+    // Remove the 'replace file' functionality.
+    $form['multiform'][$key]['replace_upload']['#access'] = FALSE;
+
+    // Remove any actions.
     $form['multiform'][$key]['actions']['#access'] = FALSE;
+
+    // Hide additional settings under a collapsible fieldset.
+    $form['multiform'][$key]['settings'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Additional settings'),
+      '#weight' => 99,
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+      // FAPI #collapsed and #collapsible not available in a render array.
+      '#attached' => array(
+        'js' => array(
+          'misc/form.js',
+          'misc/collapse.js',
+        ),
+      ),
+      '#attributes' => array(
+        'class' => array('collapsible', 'collapsed'),
+      ),
+    );
+
+    $form['multiform'][$key]['settings']['additional_settings'] = $form['multiform'][$key]['additional_settings'];
+    unset($form['multiform'][$key]['additional_settings']);
   }
 
   if (isset($form['buttons']['Delete'])) {
diff --git a/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.info b/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.info
index a4414f9f..9763f529 100644
--- a/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.info
+++ b/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.info
@@ -7,11 +7,15 @@ dependencies[] = media
 dependencies[] = multiform
 dependencies[] = plupload
 
+test_dependencies[] = multiform
+test_dependencies[] = plupload
+
 files[] = includes/MediaBrowserBulkUpload.inc
+files[] = tests/media_bulk_upload.test
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.module b/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.module
index aba72f86..9bd0d7af 100644
--- a/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.module
+++ b/drupal7/sites/all/modules/media/modules/media_bulk_upload/media_bulk_upload.module
@@ -154,11 +154,16 @@ function media_bulk_upload_forms($form_id, $args) {
   if ($form_id != 'media_edit' && (strpos($form_id, 'media_edit') === 0)) {
     $forms[$form_id] = array(
       'callback' => 'file_entity_edit',
+      'wrapper_callback' => 'media_bulk_upload_prepare_edit_form',
     );
   }
   return $forms;
 }
 
+function media_bulk_upload_prepare_edit_form($form, &$form_state) {
+  form_load_include($form_state, 'inc', 'file_entity', 'file_entity.pages');
+}
+
 /**
  * Access callback for the media-multi form.
  *
diff --git a/drupal7/sites/all/modules/media/modules/media_bulk_upload/tests/media_bulk_upload.test b/drupal7/sites/all/modules/media/modules/media_bulk_upload/tests/media_bulk_upload.test
new file mode 100644
index 00000000..6bd21987
--- /dev/null
+++ b/drupal7/sites/all/modules/media/modules/media_bulk_upload/tests/media_bulk_upload.test
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Tests for media_bulk_upload.module.
+ */
+
+/**
+ * Provides methods specifically for testing Media Bulk Upload module's bulk file uploading capabilities.
+ */
+class MediaBulkUploadTestHelper extends DrupalWebTestCase {
+  function setUp() {
+    // Since this is a base class for many test cases, support the same
+    // flexibility that DrupalWebTestCase::setUp() has for the modules to be
+    // passed in as either an array or a variable number of string arguments.
+    $modules = func_get_args();
+    if (isset($modules[0]) && is_array($modules[0])) {
+      $modules = $modules[0];
+    }
+    $modules[] = 'media_bulk_upload';
+    parent::setUp($modules);
+  }
+
+  /**
+   * Retrieves a sample file of the specified type.
+   */
+  function getTestFile($type_name, $size = NULL) {
+    // Get a file to upload.
+    $file = current($this->drupalGetTestFiles($type_name, $size));
+
+    // Add a filesize property to files as would be read by file_load().
+    $file->filesize = filesize($file->uri);
+
+    return $file;
+  }
+
+  /**
+   * Get a file from the database based on its filename.
+   *
+   * @param $filename
+   *   A file filename, usually generated by $this->randomName().
+   * @param $reset
+   *   (optional) Whether to reset the internal file_load() cache.
+   *
+   * @return
+   *   A file object matching $filename.
+   */
+  function getFileByFilename($filename, $reset = FALSE) {
+    $files = file_load_multiple(array(), array('filename' => $filename), $reset);
+    // Load the first file returned from the database.
+    $returned_file = reset($files);
+    return $returned_file;
+  }
+}
+
+/**
+ * Test bulk file editing.
+ */
+class MediaBulkUploadEditTestCase extends MediaBulkUploadTestHelper {
+  public static function getInfo() {
+    return array(
+      'name' => 'Bulk file editing',
+      'description' => 'Test file editing with multiple files.',
+      'group' => 'Media Bulk Upload',
+      'dependencies' => array('multiform', 'plupload'),
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    $web_user = $this->drupalCreateUser(array('create files', 'edit any document files', 'edit any image files'));
+    $this->drupalLogin($web_user);
+  }
+
+  /**
+   * Tests editing with multiple files.
+   */
+  function testBulkFileEditing() {
+    $files = array();
+
+    // Create multiple files for testing.
+    foreach (array('image', 'text') as $type_name) {
+      $test_file = $this->getTestFile($type_name);
+      $file = file_save($test_file);
+      $files[$file->fid] = $file;
+    }
+
+    // Visit the bulk file edit page and verify that it performs as expected.
+    $path = media_bulk_upload_file_edit_url(array_keys($files));
+    $this->drupalGet($path);
+
+    foreach ($files as $file) {
+      // Verify that a filename for each file is present on the page.
+      $title = t('<em>Edit @type</em> @title', array('@type' => $file->type, '@title' => $file->filename));
+      $this->assertRaw('<h2>' . $title . '</h2>', 'The file has the correct filename.');
+
+      // Verify that the 'replace file' functionality is disabled.
+      $this->assertNoField('multiform[media_edit_' . $file->fid . '_' . ($file->fid - 1) . '][files][replace_upload]', 'Replace file field found.');
+
+      // Verify that the action buttons have been removed.
+      $this->assertNoLinkByHref('file/' . $file->fid);
+    }
+  }
+}
diff --git a/drupal7/sites/all/modules/media/modules/media_internet/media_internet.api.php b/drupal7/sites/all/modules/media/modules/media_internet/media_internet.api.php
index 75548f63..4a6afc5a 100644
--- a/drupal7/sites/all/modules/media/modules/media_internet/media_internet.api.php
+++ b/drupal7/sites/all/modules/media/modules/media_internet/media_internet.api.php
@@ -6,20 +6,42 @@
  */
 
 /**
- * Implements hook_media_internet_providers().
+ * Returns a list of Internet media providers for URL/embed code testing.
  *
- * Implementors return an multidim array, keyed by a class name with the
- * following elements:
- * - title
- * - image (optional)
- * - hidden: bool If the logo should be shown on form. (optional)
- * - weight (optional)
+ * @return array
+ *   A nested array of provider information, keyed by class name. This class
+ *   must implement a claim() method and may (should) extend the
+ *   @link MediaInternetBaseHandler MediaInternetBaseHandler @endlink class.
+ *   Each provider info array may have the following keys:
+ *   - title: (required) A name to be used when listing the currently supported
+ *     providers on the web tab of the media browser.
+ *   - hidden: (optional) Boolean to prevent the provider title from being
+ *     listed on the web tab of the media browser.
+ *   - weight: (optional) Integer to determine the tab order. Defaults to 0.
+ *
+ * @see hook_media_internet_providers_alter()
+ * @see media_internet_get_providers()
  */
 function hook_media_internet_providers() {
   return array(
-    'youtube' => array(
-      'title' => 'youtube',
-      'image' => 'youtube.jpg',
+    'MyModuleYouTubeHandler' => array(
+      'title' => t('YouTube'),
+      'hidden' => TRUE,
     ),
   );
 }
+
+/**
+ * Alter the list of Internet media providers.
+ *
+ * @param array $providers
+ *   The associative array of Internet media provider definitions from
+ *   hook_media_internet_providers().
+ *
+ * @see hook_media_internet_providers()
+ * @see media_internet_get_providers()
+ */
+function hook_media_internet_providers_alter(&$providers) {
+  $providers['MyModuleYouTubeHandler']['title'] = t('Google video hosting');
+  $providers['MyModuleYouTubeHandler']['weight'] = 42;
+}
diff --git a/drupal7/sites/all/modules/media/modules/media_internet/media_internet.info b/drupal7/sites/all/modules/media/modules/media_internet/media_internet.info
index a01f8a2d..56ee5796 100644
--- a/drupal7/sites/all/modules/media/modules/media_internet/media_internet.info
+++ b/drupal7/sites/all/modules/media/modules/media_internet/media_internet.info
@@ -12,9 +12,9 @@ files[] = includes/MediaInternetNoHandlerException.inc
 files[] = includes/MediaInternetValidationException.inc
 files[] = tests/media_internet.test
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/modules/media_internet/media_internet.module b/drupal7/sites/all/modules/media/modules/media_internet/media_internet.module
index c60fbd80..d94b4792 100644
--- a/drupal7/sites/all/modules/media/modules/media_internet/media_internet.module
+++ b/drupal7/sites/all/modules/media/modules/media_internet/media_internet.module
@@ -61,35 +61,39 @@ function media_internet_theme() {
 }
 
 /**
- * Gets the list of providers.
+ * Gets the list of Internet media providers.
  *
- * A "Provider" is a bit of meta-data like a title and a logo and a class which
- * can handle saving remote files.  Each provider is able to parse an embed code or URL
- * and store it as a file object in file_managed.
+ * Each 'Provider' has a title and a class which can handle saving remote files.
+ * Providers are each given a turn at parsing a user-submitted URL or embed code
+ * and, if they recognize that it belongs to a service or protocol they support,
+ * they store a representation of it as a file object in file_managed.
+ *
+ * @return array
+ *   An associative array of provider information keyed by provider name.
  */
 function media_internet_get_providers() {
   $providers = &drupal_static(__FUNCTION__);
 
   if (!isset($providers)) {
-    $cid = 'media:internet:providers';
-    if ($cache = cache_get($cid)) {
-      $providers = $cache->data;
-    }
-    else {
-      $providers = array();
-      foreach (module_implements('media_internet_providers') as $module) {
-        foreach (module_invoke($module, 'media_internet_providers') as $key => $provider) {
-          // Store the module here too for convinience.
-          $providers[$key] = $provider;
-          $providers[$key]['module'] = $module;
-          if (!isset($providers[$key]['weight'])) {
-            $providers[$key]['weight'] = 0;
-          }
+    foreach (module_implements('media_internet_providers') as $module) {
+      foreach (module_invoke($module, 'media_internet_providers') as $class => $info) {
+        $providers[$class] = $info;
+
+        // Store the name of the module which declared the provider.
+        $providers[$class]['module'] = $module;
+
+        // Assign a default value to providers which don't specify a weight.
+        if (!isset($providers[$class]['weight'])) {
+          $providers[$class]['weight'] = 0;
         }
       }
-      uasort($providers, 'drupal_sort_weight');
-      cache_set($cid, $providers);
     }
+
+    // Allow modules to alter the list of providers.
+    drupal_alter('media_internet_providers', $providers);
+
+    // Sort the providers by weight.
+    uasort($providers, 'drupal_sort_weight');
   }
 
   return $providers;
@@ -201,7 +205,7 @@ function media_internet_form_file_entity_add_upload_alter(&$form, &$form_state,
       $form['embed_code']['#title'] = t('File URL or media resource');
       $form['embed_code']['#description'] = t('Enter a URL to a file or media resource. Many media providers also support identifying media via the embed code used to embed the media into external websites.');
 
-      $form['embed_code']['#description'] = theme('media_internet_embed_help', array('description' => $form['embed_code']['#description'], 'supported_providers' => implode(' ', $providers)));
+      $form['embed_code']['#description'] = theme('media_internet_embed_help', array('description' => $form['embed_code']['#description'], 'supported_providers' => implode(', ', $providers)));
     }
 
     $form['#validators'] = array();
diff --git a/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet.test b/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet.test
index 9d67ac16..04b3243b 100644
--- a/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet.test
+++ b/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet.test
@@ -21,6 +21,26 @@ class MediaInternetTestHelper extends DrupalWebTestCase {
     parent::setUp($modules);
   }
 
+  /**
+   * Retrieves a sample file of the specified type.
+   */
+  function getTestFile($type_name, $size = NULL) {
+    // Get a file to upload.
+    $file = current($this->drupalGetTestFiles($type_name, $size));
+
+    // Add a filesize property to files as would be read by file_load().
+    $file->filesize = filesize($file->uri);
+
+    return $file;
+  }
+
+  /**
+   * Retrieves the fid of the last inserted file.
+   */
+  function getLastFileId() {
+    return (int) db_query('SELECT MAX(fid) FROM {file_managed}')->fetchField();
+  }
+
   /**
    * Get a file from the database based on its filename.
    *
@@ -38,6 +58,21 @@ class MediaInternetTestHelper extends DrupalWebTestCase {
     $returned_file = reset($files);
     return $returned_file;
   }
+
+  protected function createFileType($overrides = array()) {
+    $type = new stdClass();
+    $type->type = 'test';
+    $type->label = "Test";
+    $type->description = '';
+    $type->mimetypes = array('image/jpeg', 'image/gif', 'image/png', 'image/tiff');
+
+    foreach ($overrides as $k => $v) {
+      $type->$k = $v;
+    }
+
+    file_type_save($type);
+    return $type;
+  }
 }
 
 /**
@@ -49,7 +84,6 @@ class MediaInternetBrowserWebTabTestCase extends MediaInternetTestHelper {
       'name' => 'Media browser web tab test',
       'description' => 'Tests the media browser web tab.',
       'group' => 'Media Internet',
-      'dependencies' => array('fake'), // @todo remove when File Entity > alpha3 is released. This test currently fails on drupal.org due to testbot dependency issues.
     );
   }
 
@@ -83,45 +117,44 @@ class MediaInternetBrowserWebTabTestCase extends MediaInternetTestHelper {
 }
 
 /**
- * Test file creation through the file upload wizard with remote media.
+ * Test the default MediaInternetFileHandler provider.
  */
-class MediaInternetCreationTestCase extends MediaInternetTestHelper {
+class MediaInternetRemoteFileTestCase extends MediaInternetTestHelper {
   public static function getInfo() {
     return array(
-      'name' => 'Remote media file creation',
-      'description' => 'Test file creation with remote media.',
+      'name' => 'Remote media file handler provider',
+      'description' => 'Test the default remote file handler provider.',
       'group' => 'Media Internet',
-      'dependencies' => array('fake'), // @todo remove when File Entity > alpha3 is released. This test currently fails on drupal.org due to testbot dependency issues.
     );
   }
 
   function setUp() {
     parent::setUp();
 
-    $web_user = $this->drupalCreateUser(array('create files', 'add media from remote sources', 'edit own document files'));
+    // Disable the private file system which is automatically enabled by
+    // DrupalTestCase so we can test the upload wizard correctly.
+    variable_del('file_private_path');
+
+    $web_user = $this->drupalCreateUser(array('create files', 'add media from remote sources'));
     $this->drupalLogin($web_user);
   }
 
   /**
-   * Tests file creation with remote media.
+   * Tests the default remote file handler.
    */
-  function testRemoteMediaFileCreation() {
-    // Create a file.
+  function testRemoteFileHandling() {
+    // Step 1: Add a basic document file by providing a URL to the file.
     $edit = array();
     $edit['embed_code'] = file_create_url('README.txt');
     $this->drupalPost('file/add/web', $edit, t('Next'));
 
-    // Step 2: Scheme selection
-    if ($this->xpath('//input[@name="scheme"]')) {
-      $this->drupalPost(NULL, array(), t('Next'));
-    }
-
-    // Check that the document file has been uploaded.
-    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Document', '%name' => 'README.txt')), t('Document file uploaded.'));
-
     // Check that the file exists in the database.
-    $file = $this->getFileByFilename('README.txt');
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
     $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the video file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Document', '%name' => $file->filename)), t('Document file uploaded.'));
   }
 }
 
@@ -134,43 +167,228 @@ class MediaInternetProviderTestCase extends MediaInternetTestHelper {
       'name' => 'Custom media provider test',
       'description' => 'Tests the custom media provider APIs.',
       'group' => 'Media Internet',
-      'dependencies' => array('fake'), // @todo remove when File Entity > alpha3 is released. This test currently fails on drupal.org due to testbot dependency issues.
     );
   }
 
   function setUp() {
     parent::setUp('media_internet_test');
 
-    $web_user = $this->drupalCreateUser(array('access media browser', 'create files', 'add media from remote sources', 'edit own video files'));
+    // Disable the private file system which is automatically enabled by
+    // DrupalTestCase so we can test the upload wizard correctly.
+    variable_del('file_private_path');
+
+    // Enable media_internet_test.module's hook_media_internet_providers()
+    // implementation.
+    variable_set('media_internet_test_media_internet_providers', TRUE);
+
+    $web_user = $this->drupalCreateUser(array('create files', 'view own private files', 'add media from remote sources'));
     $this->drupalLogin($web_user);
   }
 
   /**
-   * Tests file creation with a custom media provider.
+   * Test the basic file upload wizard functionality.
    */
-  function testFilesBrowserSort() {
+  function testMediaInternetCustomProviderWizardBasic() {
     $this->drupalGet('file/add/web');
     $this->assertResponse(200);
 
     // Check that the provider is listed as supported.
-    $supported_providers = 'Media Internet Test';
-    $this->assertRaw(t('Supported internet media providers: !providers.', array('!providers' => '<strong>' . $supported_providers . '</strong>')), t('The example media provider is enabled.'));
+    $this->assertRaw(t('Supported internet media providers: !providers.', array('!providers' => '<strong>' . 'Media Internet Test' . '</strong>')), t('The example media provider is enabled.'));
 
-    // Create a file.
+    // Enable media_internet_test.module's
+    // hook_media_browser_plugin_info_alter_alter() implementation and ensure it
+    // is working as designed.
+    variable_set('media_internet_test_media_internet_providers_alter', TRUE);
+
+    $this->drupalGet('file/add/web');
+    $this->assertRaw(t('Supported internet media providers: !providers.', array('!providers' => '<strong>' . 'Altered provider title' . '</strong>')), t('The example media provider was successfully altered.'));
+
+    // Step 1: Upload a basic video file.
     $edit = array();
     $edit['embed_code'] = 'http://www.example.com/video/123';
     $this->drupalPost('file/add/web', $edit, t('Next'));
 
-    // Step 2: Scheme selection
-    if ($this->xpath('//input[@name="scheme"]')) {
-      $this->drupalPost(NULL, array(), t('Next'));
-    }
+    // Check that the file exists in the database.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+    $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the video file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Video', '%name' => $file->filename)), t('Video file uploaded.'));
+  }
+
+  /**
+   * Test the file upload wizard type step.
+   */
+  function testMediaInternetCustomProviderWizardTypes() {
+    // Create multiple file types with the same mime types.
+    $this->createFileType(array('type' => 'video1', 'label' => 'Video 1', 'mimetypes' => array('video/mediainternettest')));
+    $this->createFileType(array('type' => 'video2', 'label' => 'Video 2', 'mimetypes' => array('video/mediainternettest')));
+
+    // Step 1: Upload a basic video file.
+    $edit = array();
+    $edit['embed_code'] = 'http://www.example.com/video/123';
+    $this->drupalPost('file/add/web', $edit, t('Next'));
+
+    // Step 2: File type selection.
+    $edit = array();
+    $edit['type'] = 'video2';
+    $this->drupalPost(NULL, $edit, t('Next'));
+
+    // Check that the file exists in the database.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+    $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the video file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Video 2', '%name' => $file->filename)), t('Video 2 file uploaded.'));
+  }
+
+  /**
+   * Test the file upload wizard scheme step.
+   */
+  function testMediaInternetCustomProviderWizardSchemes() {
+    // Enable the private file system.
+    variable_set('file_private_path', $this->private_files_directory);
+
+    // Step 1: Upload a basic video file.
+    $edit = array();
+    $edit['embed_code'] = 'http://www.example.com/video/123';
+    $this->drupalPost('file/add/web', $edit, t('Next'));
+
+    // Step 3: Users should not be able to select a scheme for files with
+    // read-only stream wrappers.
+    $this->assertNoFieldByName('scheme');
+
+    // Check that the file exists in the database.
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
+    $this->assertTrue($file, t('File found in database.'));
 
     // Check that the video file has been uploaded.
-    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Video', '%name' => 'Drupal')), t('Video file uploaded.'));
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Video', '%name' => $file->filename)), t('Video file uploaded.'));
+  }
+
+  /**
+   * Test the file upload wizard field step.
+   */
+  function testMediaInternetCustomProviderWizardFields() {
+    $filename = $this->randomName();
+
+    // Add a text field to the video file type.
+    $field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = array('field_name' => $field_name, 'type' => 'text');
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'file',
+      'bundle' => 'video',
+      'label' => $this->randomName() . '_label',
+    );
+    field_create_instance($instance);
+
+    // Step 1: Upload a basic video file.
+    $edit = array();
+    $edit['embed_code'] = 'http://www.example.com/video/123';
+    $this->drupalPost('file/add/web', $edit, t('Next'));
+
+    // Step 4: Attached fields.
+    $edit = array();
+    $edit['filename'] = $filename;
+    $edit[$field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName();
+    $this->drupalPost(NULL, $edit, t('Save'));
 
     // Check that the file exists in the database.
-    $file = $this->getFileByFilename('Drupal');
+    $fid = $this->getLastFileId();
+    $file = file_load($fid);
     $this->assertTrue($file, t('File found in database.'));
+
+    // Check that the video file has been uploaded.
+    $this->assertRaw(t('!type %name was uploaded.', array('!type' => 'Video', '%name' => $filename)), t('Video file uploaded.'));
+  }
+
+  /**
+   * Test skipping each of the file upload wizard steps.
+   */
+  function testMediaInternetCustomProviderWizardStepSkipping() {
+    $filename = $this->randomName();
+
+    // Ensure that the file is affected by every step.
+    variable_set('file_private_path', $this->private_files_directory);
+
+    $this->createFileType(array('type' => 'video1', 'label' => 'Video 1', 'mimetypes' => array('video/mediainternettest')));
+    $this->createFileType(array('type' => 'video2', 'label' => 'Video 2', 'mimetypes' => array('video/mediainternettest')));
+
+    $field_name = drupal_strtolower($this->randomName() . '_field_name');
+    $field = array('field_name' => $field_name, 'type' => 'text');
+    field_create_field($field);
+    $instance = array(
+      'field_name' => $field_name,
+      'entity_type' => 'file',
+      'bundle' => 'video2',
+      'label' => $this->randomName() . '_label',
+    );
+    field_create_instance($instance);
+
+    // Test skipping each upload wizard step.
+    foreach (array('types', 'schemes', 'fields') as $step) {
+      // Step to skip.
+      switch ($step) {
+        case 'types':
+          variable_set('file_entity_file_upload_wizard_skip_file_type', TRUE);
+          break;
+        case 'schemes':
+          variable_set('file_entity_file_upload_wizard_skip_scheme', TRUE);
+          break;
+        case 'fields':
+          variable_set('file_entity_file_upload_wizard_skip_fields', TRUE);
+          break;
+      }
+
+      // Step 1: Upload a basic video file.
+      $edit = array();
+      $edit['embed_code'] = 'http://www.example.com/video/123';
+      $this->drupalPost('file/add/web', $edit, t('Next'));
+
+      // Step 2: File type selection.
+      if ($step != 'types') {
+        $edit = array();
+        $edit['type'] = 'video2';
+        $this->drupalPost(NULL, $edit, t('Next'));
+      }
+
+      // Step 3: Users should not be able to select a scheme for files with
+      // read-only stream wrappers.
+      $this->assertNoFieldByName('scheme');
+
+      // Step 4: Attached fields.
+      if ($step != 'fields') {
+        // Skipping file type selection essentially skips this step as well
+        // because the file will not be assigned a type so no fields will be
+        // available.
+        if ($step != 'types') {
+          $edit = array();
+          $edit['filename'] = $filename;
+          $edit[$field_name . '[' . LANGUAGE_NONE . '][0][value]'] = $this->randomName();
+          $this->drupalPost(NULL, $edit, t('Save'));
+        }
+      }
+
+      // Check that the file exists in the database.
+      $fid = $this->getLastFileId();
+      $file = file_load($fid);
+      $this->assertTrue($file, t('File found in database.'));
+
+      // Determine the file's file type.
+      $type = file_type_load($file->type);
+
+      // Check that the video file has been uploaded.
+      $this->assertRaw(t('!type %name was uploaded.', array('!type' => $type->label, '%name' => $file->filename)), t('Video file uploaded.'));
+
+      // Reset 'skip' variables.
+      variable_del('file_entity_file_upload_wizard_skip_file_type');
+      variable_del('file_entity_file_upload_wizard_skip_scheme');
+      variable_del('file_entity_file_upload_wizard_skip_fields');
+    }
   }
 }
diff --git a/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.info b/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.info
index 193115db..09f831c4 100644
--- a/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.info
+++ b/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.info
@@ -7,9 +7,9 @@ hidden = TRUE
 files[] = includes/MediaInternetTestStreamWrapper.inc
 files[] = includes/MediaInternetTestHandler.inc
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.module b/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.module
index ee1279aa..cfcd69a2 100644
--- a/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.module
+++ b/drupal7/sites/all/modules/media/modules/media_internet/tests/media_internet_test.module
@@ -9,6 +9,11 @@
  * Implements hook_media_internet_providers().
  */
 function media_internet_test_media_internet_providers() {
+  // Allow tests to enable or disable this hook.
+  if (!variable_get('media_internet_test_media_internet_providers', FALSE)) {
+    return array();
+  }
+
   return array(
     'MediaInternetTestHandler' => array(
       'title' => t('Media Internet Test'),
@@ -16,6 +21,18 @@ function media_internet_test_media_internet_providers() {
   );
 }
 
+/**
+ * Implements hook_media_browser_plugin_info_alter_alter().
+ */
+function media_internet_test_media_internet_providers_alter(&$providers) {
+  // Allow tests to enable or disable this hook.
+  if (!variable_get('media_internet_test_media_internet_providers_alter', FALSE)) {
+    return;
+  }
+
+  $providers['MediaInternetTestHandler']['title'] = t('Altered provider title');
+}
+
 /**
  * Implements hook_stream_wrappers().
  */
diff --git a/drupal7/sites/all/modules/media/modules/media_migrate_file_types/includes/media_migrate_file_types.pages.inc b/drupal7/sites/all/modules/media/modules/media_migrate_file_types/includes/media_migrate_file_types.pages.inc
index e88bda13..78131e88 100644
--- a/drupal7/sites/all/modules/media/modules/media_migrate_file_types/includes/media_migrate_file_types.pages.inc
+++ b/drupal7/sites/all/modules/media/modules/media_migrate_file_types/includes/media_migrate_file_types.pages.inc
@@ -150,18 +150,22 @@ function media_migrate_file_types_upgrade_file_types_confirm_submit($form, &$for
         $fields_to_move = array_diff($old_fields, $new_fields);
         $fields_to_drop = array_diff($old_fields, $fields_to_move);
 
-        db_update('field_config_instance')
-          ->fields(array('bundle' => $bundle_new->type))
-          ->condition('entity_type',  'file')
-          ->condition('bundle', $bundle_old->type)
-          ->condition('field_name', $fields_to_move, 'IN')
-          ->execute();
-
-        db_delete('field_config_instance')
-          ->condition('entity_type',  'file')
-          ->condition('bundle', $bundle_old->type)
-          ->condition('field_name', $fields_to_drop, 'IN')
-          ->execute();
+        if (!empty($fields_to_move)) {
+          db_update('field_config_instance')
+            ->fields(array('bundle' => $bundle_new->type))
+            ->condition('entity_type',  'file')
+            ->condition('bundle', $bundle_old->type)
+            ->condition('field_name', $fields_to_move, 'IN')
+            ->execute();
+        }
+
+        if (!empty($fields_to_drop)) {
+          db_delete('field_config_instance')
+            ->condition('entity_type',  'file')
+            ->condition('bundle', $bundle_old->type)
+            ->condition('field_name', $fields_to_drop, 'IN')
+            ->execute();
+        }
 
         field_cache_clear();
         module_invoke_all('field_attach_rename_bundle', 'file', $bundle_old->type, $bundle_new->type);
diff --git a/drupal7/sites/all/modules/media/modules/media_migrate_file_types/media_migrate_file_types.info b/drupal7/sites/all/modules/media/modules/media_migrate_file_types/media_migrate_file_types.info
index 0031d93f..b872ec51 100644
--- a/drupal7/sites/all/modules/media/modules/media_migrate_file_types/media_migrate_file_types.info
+++ b/drupal7/sites/all/modules/media/modules/media_migrate_file_types/media_migrate_file_types.info
@@ -8,9 +8,9 @@ dependencies[] = media
 
 configure = admin/structure/file-types/upgrade
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc b/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc
index 44360b3d..73d6b5ff 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.filter.inc
@@ -56,6 +56,7 @@ function media_wysiwyg_parse_css_declarations($declarations) {
  * @see hook_media_wysiwyg_token_to_markup_alter()
  */
 function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
+  static $recursion_stop;
   $settings = array();
   $match = str_replace("[[", "", $match);
   $match = str_replace("]]", "", $match);
@@ -107,6 +108,13 @@ function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
     if (!$file) {
       throw new Exception('Could not load media object');
     }
+    // Check if we've got a recursion. Happens because a file_load() may
+    // triggers file_entity_is_page() which then again triggers a file load.
+    if (isset($recursion_stop[$file->fid])) {
+      return '';
+    }
+    $recursion_stop[$file->fid] = TRUE;
+
     $tag_info['file'] = $file;
 
     // The class attributes is a string, but drupal requires it to be
@@ -117,6 +125,9 @@ function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
 
     // Grab the potentially overrided fields from the file.
     $fields = media_wysiwyg_filter_field_parser($tag_info);
+    foreach ($fields as $key => $value) {
+      $file->{$key} = $value;
+    }
 
     $attributes = is_array($tag_info['attributes']) ? $tag_info['attributes'] : array();
     $attribute_whitelist = variable_get('media_wysiwyg_wysiwyg_allowed_attributes', _media_wysiwyg_wysiwyg_allowed_attributes_default());
@@ -165,7 +176,7 @@ function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
 
   if ($wysiwyg) {
     $settings['wysiwyg'] = $wysiwyg;
-    // If sending markup to a WYSIWYG, we need to pass the file infomation so
+    // If sending markup to a WYSIWYG, we need to pass the file information so
     // that an inline macro can be generated when the WYSIWYG is detached.
     // The WYSIWYG plugin is expecting this information in the
     // Drupal.settings.mediaDataMap variable.
@@ -178,11 +189,16 @@ function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
     );
     drupal_add_js(array('mediaDataMap' => array($file->fid => $data)), 'setting');
     $element['#attributes']['data-fid'] = $file->fid;
+    $element['#attributes']['data-media-element'] = '1';
     $element['#attributes']['class'][] = 'media-element';
   }
   else {
     // Display the field elements.
     $element = array();
+    // Render the file entity, for sites using the file_entity rendering method.
+    if (variable_get('media_wysiwyg_default_render', 'file_entity') == 'file_entity') {
+      $element['content'] = file_view($file, $tag_info['view_mode']);
+    }
     $element['content']['file'] = media_wysiwyg_get_file_without_label($file, $tag_info['view_mode'], $settings);
     // Overwrite or set the file #alt attribute if it has been set in this
     // instance.
@@ -194,9 +210,12 @@ function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
     if (!empty($element['content']['file']['#attributes']['title'])) {
       $element['content']['file']['#title'] = $element['content']['file']['#attributes']['title'];
     }
-    field_attach_prepare_view('file', array($file->fid => $file), $tag_info['view_mode']);
-    entity_prepare_view('file', array($file->fid => $file));
-    $element['content'] += field_attach_view('file', $file, $tag_info['view_mode']);
+    // For sites using the legacy field_attach rendering method, attach fields.
+    if (variable_get('media_wysiwyg_default_render', 'file_entity') == 'field_attach') {
+      field_attach_prepare_view('file', array($file->fid => $file), $tag_info['view_mode']);
+      entity_prepare_view('file', array($file->fid => $file));
+      $element['content'] += field_attach_view('file', $file, $tag_info['view_mode']);
+    }
     if (count(element_children($element['content'])) > 1) {
       // Add surrounding divs to group them together.
       // We dont want divs when there are no additional fields to allow files
@@ -208,9 +227,17 @@ function media_wysiwyg_token_to_markup($match, $wysiwyg = FALSE) {
         'media-' . $element['content']['file']['#view_mode']
       );
     }
+
+    // Conditionally add a pre-render if the media filter output is be cached.
+    $filters = filter_get_filters();
+    if (!isset($filters['media_filter']['cache']) || $filters['media_filter']['cache']) {
+      $element['#pre_render'][] = 'media_wysiwyg_pre_render_cached_filter';
+    }
   }
   drupal_alter('media_wysiwyg_token_to_markup', $element, $tag_info, $settings);
-  return drupal_render($element);
+  $output = drupal_render($element);
+  unset($recursion_stop[$file->fid]);
+  return $output;
 }
 
 /**
@@ -241,33 +268,6 @@ function media_wysiwyg_filter_field_parser($tag_info) {
   return $fields;
 }
 
-/**
- * Builds a map of media tags in the element.
- *
- * Builds a map of the media tags in an element that are being rendered to their
- * rendered HTML. The map is stored in JS, so we can transform them when the
- * editor is being displayed.
- */
-function media_wysiwyg_pre_render_text_format($element) {
-  // filter_process_format() copies properties to the expanded 'value' child
-  // element.
-  if (!isset($element['format'])) {
-    return $element;
-  }
-
-  $field = &$element['value'];
-  $settings = array(
-    'field' => $field['#id'],
-  );
-
-  $tagmap = _media_wysiwyg_generate_tagMap($field['#value']);
-
-  if (isset($tagmap)) {
-    drupal_add_js(array('tagmap' => $tagmap), 'setting');
-  }
-  return $element;
-}
-
 /**
  * Creates map of inline media tags.
  *
@@ -357,3 +357,16 @@ function media_wysiwyg_get_wysiwyg_allowed_view_modes($file) {
   drupal_alter('media_wysiwyg_wysiwyg_allowed_view_modes', $view_modes, $file);
   return $view_modes;
 }
+
+/**
+ * #pre_render callback: Modify the element if the render cache is filtered.
+ */
+function media_wysiwyg_pre_render_cached_filter($element) {
+  // Remove contextual links since they are not compatible with cached filtered
+  // text.
+  if (isset($element['content']['#contextual_links'])) {
+    unset($element['content']['#contextual_links']);
+  }
+
+  return $element;
+}
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.pages.inc b/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.pages.inc
index ab1a845d..72653b8f 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.pages.inc
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/includes/media_wysiwyg.pages.inc
@@ -83,7 +83,7 @@ function media_wysiwyg_format_form($form, &$form_state, $file) {
       they are inserted into an editor.')
   );
 
-  // Add fields from the file, so that we can override them if neccesary.
+  // Add fields from the file, so that we can override them if necessary.
   $form['options']['fields'] = array();
   foreach ($fields as $field_name => $field_value) {
     $file->{$field_name} = $field_value;
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.filter.js b/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.filter.js
index 5ac10ec4..efccd59c 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.filter.js
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.filter.js
@@ -46,6 +46,7 @@
             var source = Drupal.settings.mediaSourceMap[media_definition.fid];
             media = document.createElement(source.tagName);
             media.src = source.src;
+            media.innerHTML = source.innerHTML;
           }
 
           // Apply attributes.
@@ -72,25 +73,39 @@
       // Rewrite the tagmap in case any of the macros have changed.
       Drupal.settings.tagmap = {};
 
-      // Wrap the content to be able to use replaceWith() and html().
-      content = $('<div>').append(content);
-      var media = $('.media-element', content);
-
-      if (media.length) {
-        // Replace all media elements with their respective macros.
-        media.replaceWith(function() {
-          var el = $(this),
-            macro = Drupal.media.filter.create_macro(el);
-
-          // Store the markup for more efficient rendering later.
-          // @see replaceTokenWidthPlaceholder()
-          Drupal.settings.tagmap[macro] = Drupal.media.filter.outerHTML(el);
-
-          return macro;
-        });
+      // Replace all media placeholders with their JSON macro representations.
+      //
+      // There are issues with using jQuery to parse the WYSIWYG content (see
+      // http://drupal.org/node/1280758), and parsing HTML with regular
+      // expressions is a terrible idea (see http://stackoverflow.com/a/1732454/854985)
+      //
+      // WYSIWYG editors act wacky with complex placeholder markup anyway, so an
+      // image is the most reliable and most usable anyway: images can be moved by
+      // dragging and dropping, and can be resized using interactive handles.
+      //
+      // Media requests a WYSIWYG place holder rendering of the file by passing
+      // the wysiwyg => 1 flag in the settings array when calling
+      // media_get_file_without_label().
+      //
+      // Finds the media-element class.
+      var classRegex = 'class=[\'"][^\'"]*?media-element';
+      // Image tag with the media-element class.
+      var regex = '<img[^>]+' + classRegex + '[^>]*?>';
+      // Or a span with the media-element class (used for documents).
+      // \S\s catches any character, including a linebreak; JavaScript does not
+      // have a dotall flag.
+      regex += '|<span[^>]+' + classRegex + '[^>]*?>[\\S\\s]+?</span>';
+      var matches = content.match(RegExp(regex, 'gi'));
+      if (matches) {
+        for (i = 0; i < matches.length; i++) {
+          markup = matches[i];
+          macro = Drupal.media.filter.create_macro($(markup));
+          Drupal.settings.tagmap[macro] = markup;
+          content = content.replace(markup, macro);
+        }
       }
 
-      return content.html();
+      return content;
     },
 
     /**
@@ -129,7 +144,8 @@
         Drupal.media.filter.ensureSourceMap();
         Drupal.settings.mediaSourceMap[info.fid] = {
           tagName: element[0].tagName,
-          src: element[0].src
+          src: element[0].src,
+          innerHTML: element[0].innerHTML
         }
       }
 
@@ -142,14 +158,20 @@
       // Store the fid in the DOM to retrieve the data from the info map.
       element.attr('data-fid', info.fid);
 
-      // Add media-element class so we can find markup element later.
-      var classes = ['media-element'];
+      // Add data-media-element attribute so we can find the markup element later.
+      element.attr('data-media-element', '1')
 
+      var classes = ['media-element'];
       if (info.view_mode) {
         classes.push('file-' + info.view_mode.replace(/_/g, '-'));
       }
       element.addClass(classes.join(' '));
 
+      // Apply link_text if present.
+      if (info.link_text) {
+        $('a', element).html(info.link_text);
+      }
+
       return element;
     },
 
@@ -162,6 +184,10 @@
     create_macro: function (element) {
       var file_info = Drupal.media.filter.extract_file_info(element);
       if (file_info) {
+        if (typeof file_info.link_text == 'string') {
+          // Make sure the link_text-html-tags are properly escaped.
+          file_info.link_text = file_info.link_text.replace(/</g, '&lt;').replace(/>/g, '&gt;');
+        }
         return '[[' + JSON.stringify(file_info) + ']]';
       }
       return false;
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.format_form.js b/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.format_form.js
index f9b16f43..4345a345 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.format_form.js
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/media_wysiwyg.format_form.js
@@ -42,12 +42,12 @@ Drupal.media.formatForm.getOptions = function () {
       field.name = field.name.replace(/\[format\]/i, '[value]');
       field.key  = 'edit-' + field.name.replace(/[_\[]/g, '-').replace(/[\]]/g, '');
 
-      if (Drupal.wysiwyg.instances[field.key]) {
+      if (Drupal.wysiwyg && Drupal.wysiwyg.instances[field.key]) {
         // Retrieve the content from the WYSIWYG instance.
         ret[field.name] = Drupal.wysiwyg.instances[field.key].getContent();
 
-        // Escape the double-quotes and encode it to play nicely within JSON.
-        ret[field.name] = encodeURIComponent(ret[field.name].replace(/"/g, '\\"'));
+        // Encode the content to play nicely within JSON.
+        ret[field.name] = encodeURIComponent(ret[field.name]);
       }
     }
   });
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/wysiwyg-media.js b/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/wysiwyg-media.js
index af99097b..d694b85b 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/wysiwyg-media.js
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/js/wysiwyg-media.js
@@ -20,7 +20,7 @@ Drupal.wysiwyg.plugins.media = {
    *   A DOM element
    */
   isNode: function(node) {
-    return $(node).is('img.media-element');
+    return $(node).is('img[data-media-element]');
   },
 
   /**
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.ckeditor.inc b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.ckeditor.inc
index 236ef4bf..a00b1583 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.ckeditor.inc
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.ckeditor.inc
@@ -6,32 +6,20 @@
  */
 
 /**
- * Implements hook_ckeditor_plugin().
+ * Implements hook_ckeditor_plugin_alter().
  */
-function media_wysiwyg_ckeditor_plugin() {
-  return array(
-    'media' => array(
-      'name' => 'media',
-      'desc' => t('Plugin for inserting images from Drupal media module'),
-      'path' => base_path() . drupal_get_path('module', 'media_wysiwyg') . '/wysiwyg_plugins/media_ckeditor/',
-      'buttons' => array(
-        'Media' => array(
-          'icon' => 'images/icon.gif',
-          'label' => 'Add media',
-        ),
+function media_wysiwyg_ckeditor_plugin_alter(&$plugins) {
+  // Override the default CKEditor Media plugin.
+  $plugins['media'] = array(
+    'name' => 'media',
+    'desc' => t('Plugin for inserting images from Drupal media module'),
+    'path' => '%base_path%' . drupal_get_path('module', 'media_wysiwyg') . '/wysiwyg_plugins/media_ckeditor/',
+    'buttons' => array(
+      'Media' => array(
+        'icon' => 'images/icon.gif',
+        'label' => 'Add media',
       ),
-      'default' => 'f',
     ),
+    'default' => 'f',
   );
 }
-
-/**
- * Implements hook_ckeditor_plugin_alter().
- */
-function media_wysiwyg_ckeditor_plugin_alter(&$plugins) {
-  // To ensure the ckeditor media integration is done by this module all other
-  // integrations are overwritten here. However additionally added keys will be
-  // left intact.
-  $default_plugin = media_wysiwyg_ckeditor_plugin();
-  $plugins['media'] = $default_plugin['media'] + $plugins['media'];
-}
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.info b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.info
index a88618bd..60191dea 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.info
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.info
@@ -15,9 +15,9 @@ files[] = tests/media_wysiwyg.macro.test
 
 configure = admin/config/media/browser
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.install b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.install
index 6d2d5e49..a0a0d798 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.install
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.install
@@ -18,3 +18,37 @@ function media_wysiwyg_uninstall() {
   variable_del('media_wysiwyg_wysiwyg_allowed_attributes');
   variable_del('media_wysiwyg_wysiwyg_browser_plugins');
 }
+
+/**
+ * Implements hook_update_dependencies().
+ */
+function media_wysiwyg_update_dependencies() {
+  // Ensure the "access media browser" permission is granted to users before
+  // using it to grant the "use media wysiwyg" permission.
+  $dependencies['media_wysiwyg'][7201] = array(
+    'media' => 7226,
+  );
+}
+
+/**
+ * Grant existing user access to new media wysiwyg permission.
+ */
+function media_wysiwyg_update_7201() {
+  $roles = user_roles(TRUE, 'access media browser');
+  foreach ($roles as $rid => $role) {
+    user_role_grant_permissions($rid, array('use media wysiwyg'));
+  }
+
+  return t('Use Media WYSIWYG permission was granted to: @roles.', array(
+    '@roles' => check_plain(implode(', ', $roles)),
+  ));
+}
+
+/**
+ * Use the legacy file entity rendering method for existing sites.
+ *
+ * Existing sites can change this setting at admin/config/media/browser.
+ */
+function media_wysiwyg_update_7202() {
+  variable_set('media_wysiwyg_default_render', 'field_attach');
+}
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.module b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.module
index 1fb7a834..162e60bb 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.module
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/media_wysiwyg.module
@@ -31,12 +31,14 @@ function media_wysiwyg_hook_info() {
  * Implements hook_menu().
  */
 function media_wysiwyg_menu() {
+  $items = array();
+
   $items['media/%file/format-form'] = array(
     'title' => 'Style selector',
     'description' => 'Choose a format for a piece of media',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('media_wysiwyg_format_form', 1),
-    'access callback' => 'file_entity_access',
+    'access callback' => 'media_wysiwyg_access',
     'access arguments' => array('view', 1),
     'file' => 'includes/media_wysiwyg.pages.inc',
     'theme callback' => 'media_dialog_get_theme_name',
@@ -46,6 +48,27 @@ function media_wysiwyg_menu() {
   return $items;
 }
 
+/**
+ * Implements hook_permission().
+ */
+function media_wysiwyg_permission() {
+  return array(
+    'use media wysiwyg' => array(
+      'title' => t('Use Media WYSIWYG in an editor'),
+      // Marked restrict because the WYSIWYG forms generate image derivatives,
+      // which could lead to a DoS security vulnerability.
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
+/**
+ * Access callback for WYSIWYG Media.
+ */
+function media_wysiwyg_access($op, $file = NULL, $account = NULL) {
+  return user_access('use media wysiwyg', $account) && file_entity_access($op, $file, $account);
+}
+
 /**
  * Implements hook_element_info_alter().
  */
@@ -53,6 +76,69 @@ function media_wysiwyg_element_info_alter(&$types) {
   $types['text_format']['#pre_render'][] = 'media_wysiwyg_pre_render_text_format';
 }
 
+/**
+ * Builds a map of media tags in the element.
+ *
+ * Builds a map of the media tags in an element that are being rendered to their
+ * rendered HTML. The map is stored in JS, so we can transform them when the
+ * editor is being displayed.
+ */
+function media_wysiwyg_pre_render_text_format($element) {
+  // filter_process_format() copies properties to the expanded 'value' child
+  // element.
+  if (!isset($element['format'])) {
+    return $element;
+  }
+
+  $field = &$element['value'];
+  $settings = array(
+    'field' => $field['#id'],
+  );
+
+  if (!isset($field['#value'])) {
+    return $element;
+  }
+
+  $tagmap = _media_wysiwyg_generate_tagMap($field['#value']);
+
+  if (isset($tagmap)) {
+    $element['#attached']['js'][] = array(
+      'data' => array(
+        'tagmap' => $tagmap,
+      ),
+      'type' => 'setting',
+    );
+  }
+
+  // Load the media browser library.
+  $element['#attached']['library'][] = array('media', 'media_browser');
+  $element['#attached']['library'][] = array('media', 'media_browser_settings');
+
+  // Add wysiwyg-specific settings.
+  $settings = array('wysiwyg_allowed_attributes' => variable_get('media_wysiwyg_wysiwyg_allowed_attributes', _media_wysiwyg_wysiwyg_allowed_attributes_default()));
+  $element['#attached']['js'][] = array(
+    'data' => array(
+      'media' => $settings,
+    ),
+    'type' => 'setting',
+  );
+
+  // Add filter handling.
+  $element['#attached']['js'][] = drupal_get_path('module', 'media_wysiwyg') . '/js/media_wysiwyg.filter.js';
+
+  // Add CKEditor-specific JS.
+  if (module_exists('ckeditor')) {
+    $element['#attached']['js'][] = array(
+      'data' => drupal_get_path('module', 'media_wysiwyg') . '/wysiwyg_plugins/media_ckeditor/library.js',
+      'type' => 'file',
+      'scope' => 'footer',
+      'weight' => -20,
+    );
+  }
+
+  return $element;
+}
+
 /**
  * Implements hook_form_FORM_ID_alter().
  */
@@ -121,6 +207,17 @@ function media_wysiwyg_form_media_admin_config_browser_alter(&$form, &$form_stat
     );
   }
 
+  $form['wysiwyg']['media_wysiwyg_default_render'] = array(
+    '#type' => 'radios',
+    '#title' => t('How should file entities be rendered within a text field?'),
+    '#description' => t("Full file entity rendering is the best choice for most sites. It respects the file entity's display settings specified at admin/structure/file-types. If your site already uses the legacy method, note that changing this option will affect your site's markup. Testing it on a non-production site is recommended."),
+    '#options' => array(
+      'file_entity' => 'Full file entity rendering',
+      'field_attach' => 'Legacy rendering (using field attach)',
+    ),
+    '#default_value' => variable_get('media_wysiwyg_default_render', 'file_entity'),
+  );
+
   $form['wysiwyg']['media_wysiwyg_wysiwyg_allowed_types'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Allowed types in WYSIWYG'),
@@ -158,35 +255,6 @@ function media_wysiwyg_filter_info() {
   return $filters;
 }
 
-/**
- * Prepares the page to be able to launch the media browser.
- *
- * Defines default variables.
- */
-function media_wysiwyg_include_browser_js() {
-  static $included;
-  if ($included) {
-    return;
-  }
-  $included = TRUE;
-  module_load_include('inc', 'media', 'includes/media.browser');
-  $javascript = media_browser_js();
-  foreach ($javascript as $key => $definitions) {
-    foreach ($definitions as $definition) {
-      $function = 'drupal_add_' . $key;
-      // Since the arguments to pass are variable, use call_user_func_array().
-      // This will not handle all potential drupal_add_*() functions directly
-      // but covers the js and library needed here, which are unlikely to be
-      // expanded since this function is only a workaround for a wysiwyg
-      // limitation.
-      call_user_func_array($function, $definition);
-    }
-  }
-  // Add wysiwyg-specific settings.
-  $settings = array('wysiwyg_allowed_attributes' => variable_get('media_wysiwyg_wysiwyg_allowed_attributes', _media_wysiwyg_wysiwyg_allowed_attributes_default()));
-  drupal_add_js(array('media' => $settings), 'setting');
-}
-
 /**
  * Implements hook_wysiwyg_include_directory().
  */
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media.inc b/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media.inc
index a61c7134..9cd03bbd 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media.inc
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media.inc
@@ -9,16 +9,6 @@
  * Implements WYSIWYG's hook_INCLUDE_plugin().
  */
 function media_wysiwyg_media_plugin() {
-  // Include the required browser JS.
-  // @todo: wyswiyg should allow libraries and multiple js files
-  // to be defined by this hook.
-  // @see http://drupal.org/node/1039076
-  media_wysiwyg_include_browser_js();
-
-  // Add the filter handling.
-  drupal_add_js(drupal_get_path('module', 'media_wysiwyg') . '/js/media_wysiwyg.filter.js');
-
-  // Plugin definition.
   $plugins['media'] = array(
     'title' => variable_get('media_wysiwyg_wysiwyg_title', t('Media browser')),
     'vendor url' => 'http://drupal.org/project/media',
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media_ckeditor/library.js b/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media_ckeditor/library.js
index a1f33374..b097d170 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media_ckeditor/library.js
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg/wysiwyg_plugins/media_ckeditor/library.js
@@ -13,7 +13,7 @@
      */
     invoke: function (data, settings, instanceId) {
       if (data.format == 'html') {
-        if (jQuery(data.node).is('.media-element')) {
+        if (jQuery(data.node).is('[data-media-element]')) {
           // Change the view mode for already-inserted media.
           var mediaFile = Drupal.media.filter.extract_file_info(jQuery(data.node));
           Drupal.media.popups.mediaStyleSelector(mediaFile, function (mediaFiles) {
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.info b/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.info
index 765a7a17..a17131e0 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.info
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.info
@@ -9,9 +9,9 @@ configure = admin/config/media/wysiwyg-view-mode
 
 files[] = media_wysiwyg_view_mode.test
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.test b/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.test
index a51dc2fa..3d27e074 100644
--- a/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.test
+++ b/drupal7/sites/all/modules/media/modules/media_wysiwyg_view_mode/media_wysiwyg_view_mode.test
@@ -12,7 +12,7 @@ class MediaWYSIWYGViewModeTestHelper extends MediaWYSIWYGTestHelper {
   function setUp() {
     parent::setUp('media_wysiwyg_view_mode');
 
-    $web_user = $this->drupalCreateUser(array('administer media wysiwyg view mode', 'view files'));
+    $web_user = $this->drupalCreateUser(array('administer media wysiwyg view mode', 'view files', 'use media wysiwyg'));
     $this->drupalLogin($web_user);
   }
 }
diff --git a/drupal7/sites/all/modules/media/modules/mediafield/mediafield.info b/drupal7/sites/all/modules/media/modules/mediafield/mediafield.info
index ed00075c..d1ab05b6 100644
--- a/drupal7/sites/all/modules/media/modules/mediafield/mediafield.info
+++ b/drupal7/sites/all/modules/media/modules/mediafield/mediafield.info
@@ -4,9 +4,9 @@ package = Media
 core = 7.x
 dependencies[] = media
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/tests/includes/MediaModuleTest.inc b/drupal7/sites/all/modules/media/tests/includes/MediaModuleTest.inc
new file mode 100644
index 00000000..5e6c5d5e
--- /dev/null
+++ b/drupal7/sites/all/modules/media/tests/includes/MediaModuleTest.inc
@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Definition of MediaModuleTest.
+ */
+
+/**
+ * Test browser plugin.
+ */
+class MediaModuleTest extends MediaBrowserPlugin {
+  /**
+   * Implements MediaBrowserPluginInterface::access().
+   */
+  public function access($account = NULL) {
+    return TRUE;
+  }
+
+  /**
+   * Implements MediaBrowserPlugin::view().
+   */
+  public function view() {
+    $build = array();
+    $build['test'] = array(
+      '#markup' => '<p>' . t('Test browser plugin output.') . '</p>',
+    );
+
+    return $build;
+  }
+}
diff --git a/drupal7/sites/all/modules/media/tests/media.test b/drupal7/sites/all/modules/media/tests/media.test
index 97e99ef1..3594aaf0 100644
--- a/drupal7/sites/all/modules/media/tests/media.test
+++ b/drupal7/sites/all/modules/media/tests/media.test
@@ -468,6 +468,49 @@ class MediaAdminTestCase extends MediaFileFieldTestCase {
   }
 }
 
+/**
+ * Tests the media hooks.
+ */
+class MediaHooksTestCase extends MediaFileFieldTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Media hooks test',
+      'description' => 'Tests the Media hooks.',
+      'group' => 'Media',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+  }
+
+  /**
+   * Tests that the media browser hooks.
+   */
+  function testMediaBrowserHooks() {
+    // Enable media_module_test.module's hook_media_browser_plugin_info()
+    // implementation and ensure it is working as designed.
+    variable_set('media_module_test_media_browser_plugin_info', TRUE);
+
+    $this->drupalGet('media/browser');
+    $this->assertRaw(t('Media module test'), 'Custom browser plugin found.');
+
+    // Enable media_module_test.module's hook_media_browser_plugin_info_alter()
+    // implementation and ensure it is working as designed.
+    variable_set('media_module_test_media_browser_plugin_info_alter', TRUE);
+
+    $this->drupalGet('media/browser');
+    $this->assertRaw(t('Altered plugin title'), 'Custom browser plugin was successfully altered.');
+
+    // Enable media_module_test.module's hook_media_browser_plugins_alter()
+    // implementation and ensure it is working as designed.
+    variable_set('media_module_test_media_browser_plugins_alter', TRUE);
+
+    $this->drupalGet('media/browser');
+    $this->assertRaw(t('Altered browser plugin output.'), 'Custom browser plugin was successfully altered before being rendered.');
+  }
+}
+
 /**
  * Tests the media browser 'Library' tab.
  */
@@ -870,15 +913,14 @@ class MediaElementSettingsTestCase extends MediaFileFieldTestCase {
     $javascript = $this->drupalGet("node/add/$type_name");
     $field_widget = array(
         'elements' => array(
-          '#edit-' . $field_name . '-' . LANGUAGE_NONE . '-0' => array(
+          '#edit-' . $field_name . '-' . LANGUAGE_NONE . '-0-upload' => array(
             'global' => array(
               'types' => array(
-                0 => 'image',
+                'image' => 'image',
               ),
               'enabledPlugins' => array(),
               'schemes' => array(
-                0 => 'public',
-                1 => 'private',
+                'public' => 'public',
               ),
               'file_directory' => '',
               'file_extensions' => 'txt',
diff --git a/drupal7/sites/all/modules/media/tests/media_module_test.info b/drupal7/sites/all/modules/media/tests/media_module_test.info
index 6e5b5416..e6267948 100644
--- a/drupal7/sites/all/modules/media/tests/media_module_test.info
+++ b/drupal7/sites/all/modules/media/tests/media_module_test.info
@@ -4,9 +4,11 @@ package = Media
 core = 7.x
 hidden = TRUE
 
-; Information added by Drupal.org packaging script on 2014-10-04
-version = "7.x-2.0-alpha4"
+files[] = includes/MediaModuleTest.inc
+
+; Information added by Drupal.org packaging script on 2015-07-14
+version = "7.x-2.0-beta1"
 core = "7.x"
 project = "media"
-datestamp = "1412422430"
+datestamp = "1436895542"
 
diff --git a/drupal7/sites/all/modules/media/tests/media_module_test.module b/drupal7/sites/all/modules/media/tests/media_module_test.module
index d4add679..49c0c409 100644
--- a/drupal7/sites/all/modules/media/tests/media_module_test.module
+++ b/drupal7/sites/all/modules/media/tests/media_module_test.module
@@ -5,6 +5,48 @@
  * Provides Media module pages for testing purposes.
  */
 
+/**
+ * Implements hook_media_browser_plugin_info().
+ */
+function media_module_test_media_browser_plugin_info() {
+  // Allow tests to enable or disable this hook.
+  if (!variable_get('media_module_test_media_browser_plugin_info', FALSE)) {
+    return array();
+  }
+
+  $info['media_module_test'] = array(
+    'title' => t('Media module test'),
+    'class' => 'MediaModuleTest',
+    'weight' => 50,
+  );
+
+  return $info;
+}
+
+/**
+ * Implements hook_media_browser_plugin_info_alter().
+ */
+function media_module_test_media_browser_plugin_info_alter(&$info) {
+  // Allow tests to enable or disable this hook.
+  if (!variable_get('media_module_test_media_browser_plugin_info_alter', FALSE)) {
+    return;
+  }
+
+  $info['media_module_test']['title'] = t('Altered plugin title');
+}
+
+/**
+ * Implements hook_media_browser_plugins_alter().
+ */
+function media_module_test_media_browser_plugins_alter(&$plugin_output) {
+  // Allow tests to enable or disable this hook.
+  if (!variable_get('media_module_test_media_browser_plugins_alter', FALSE)) {
+    return;
+  }
+
+  $plugin_output['media_module_test']['test']['#markup'] = '<p>' . t('Altered browser plugin output.') . '</p>';
+}
+
 /**
  * Implements hook_menu().
  */
