From 7f33f0c4b5d01a614a000110a7a463c97e7d6ed7 Mon Sep 17 00:00:00 2001
From: Alex Barth <alex_b@53995.no-reply.drupal.org>
Date: Tue, 27 Jul 2010 23:01:25 +0000
Subject: [PATCH] #851194: Featurize. Replace feeds_defaults with
 feeds_fast_news, feeds_import, feeds_news. Needs more testing especially of
 upgrade path.

---
 feeds.install                                 |  21 +
 feeds_defaults/feeds_defaults.defaults.inc    | 430 ----------------
 feeds_defaults/feeds_defaults.features.inc    |  35 --
 feeds_defaults/feeds_defaults.info            |   8 -
 feeds_defaults/feeds_defaults.install         |  35 --
 feeds_defaults/feeds_defaults.module          |  51 --
 feeds_defaults/tests/feeds_defaults.test      | 469 ------------------
 .../feeds_fast_news.data_default.inc          | 133 +++++
 feeds_fast_news/feeds_fast_news.features.inc  |  37 ++
 ...feeds_fast_news.feeds_importer_default.inc |  65 +++
 feeds_fast_news/feeds_fast_news.info          |  13 +
 feeds_fast_news/feeds_fast_news.install       |  46 ++
 feeds_fast_news/feeds_fast_news.module        |   3 +
 feeds_fast_news/feeds_fast_news.test          |  86 ++++
 feeds_import/feeds_import.features.inc        |  11 +
 .../feeds_import.feeds_importer_default.inc   | 120 +++++
 feeds_import/feeds_import.info                |   9 +
 feeds_import/feeds_import.module              |   3 +
 feeds_import/feeds_import.test                | 175 +++++++
 feeds_news/feeds_news.features.inc            |  51 ++
 .../feeds_news.feeds_importer_default.inc     | 117 +++++
 feeds_news/feeds_news.info                    |  14 +
 feeds_news/feeds_news.module                  |   3 +
 feeds_news/feeds_news.test                    | 149 ++++++
 feeds_news/feeds_news.views_default.inc       | 368 ++++++++++++++
 25 files changed, 1424 insertions(+), 1028 deletions(-)
 delete mode 100644 feeds_defaults/feeds_defaults.defaults.inc
 delete mode 100644 feeds_defaults/feeds_defaults.features.inc
 delete mode 100644 feeds_defaults/feeds_defaults.info
 delete mode 100644 feeds_defaults/feeds_defaults.install
 delete mode 100644 feeds_defaults/feeds_defaults.module
 delete mode 100644 feeds_defaults/tests/feeds_defaults.test
 create mode 100644 feeds_fast_news/feeds_fast_news.data_default.inc
 create mode 100644 feeds_fast_news/feeds_fast_news.features.inc
 create mode 100644 feeds_fast_news/feeds_fast_news.feeds_importer_default.inc
 create mode 100644 feeds_fast_news/feeds_fast_news.info
 create mode 100644 feeds_fast_news/feeds_fast_news.install
 create mode 100644 feeds_fast_news/feeds_fast_news.module
 create mode 100644 feeds_fast_news/feeds_fast_news.test
 create mode 100644 feeds_import/feeds_import.features.inc
 create mode 100644 feeds_import/feeds_import.feeds_importer_default.inc
 create mode 100644 feeds_import/feeds_import.info
 create mode 100644 feeds_import/feeds_import.module
 create mode 100644 feeds_import/feeds_import.test
 create mode 100644 feeds_news/feeds_news.features.inc
 create mode 100644 feeds_news/feeds_news.feeds_importer_default.inc
 create mode 100644 feeds_news/feeds_news.info
 create mode 100644 feeds_news/feeds_news.module
 create mode 100644 feeds_news/feeds_news.test
 create mode 100644 feeds_news/feeds_news.views_default.inc

diff --git a/feeds.install b/feeds.install
index 2771190f..2a585d39 100644
--- a/feeds.install
+++ b/feeds.install
@@ -492,3 +492,24 @@ function feeds_update_6009() {
   db_create_table($ret, 'feeds_push_subscriptions', $table);
   return $ret;
 }
+
+/**
+ * Enable all Feeds News, Feeds Import and Feeds fast news features.
+ */
+function feeds_update_6010() {
+  drupal_install_modules(array('feeds_news', 'feeds_import'));
+  if (module_exist('data')) {
+    drupal_install_modules(array('feeds_fast_news'));
+    drupal_set_message(t('Installed Feeds News, Feeds Fast News and Feeds Import as replacement for Feeds Defaults module.'));
+  }
+  else {
+    drupal_set_message(t('Installed Feeds News and Feeds Import as replacement for Feeds Defaults module.'));
+  }
+  if (module_exists('features')) {
+    drupal_set_message(t('Review importer configurations on admin/build/feeds and disable Feeds Features on admin/build/features if undesired configurations show up.'));
+  }
+  else {
+    drupal_set_message(t('Review importer configurations on admin/build/feeds and disable Feeds Feature modules on admin/build/modules if undesired configurations show up.'));
+  }
+  return array();
+}
diff --git a/feeds_defaults/feeds_defaults.defaults.inc b/feeds_defaults/feeds_defaults.defaults.inc
deleted file mode 100644
index 8fadbf11..00000000
--- a/feeds_defaults/feeds_defaults.defaults.inc
+++ /dev/null
@@ -1,430 +0,0 @@
-<?php
-// $Id$
-
-/**
- * @file
- * Actual function bodies for default hook definitions in
- * feeds_defaults.features.inc.
- */
-
-/**
- * Helper to implementation of hook_ctools_plugin_api().
- */
-function _feeds_defaults_ctools_plugin_api() {
-  $args = func_get_args();
-  $module = array_shift($args);
-  $api = array_shift($args);
-  if ($module == "data" && $api == "data_default") {
-    return array("version" => 1);
-  }
-  else if ($module == "feeds" && $api == "feeds_importer_default") {
-    return array("version" => 1);
-  }
-}
-
-/**
- * Helper to implementation of hook_data_default().
- */
-function _feeds_defaults_data_default() {
-  $export = array();
-  $data_table = new stdClass;
-  $data_table->disabled = FALSE; /* Edit this to true to make a default data_table disabled initially */
-  $data_table->api_version = 1;
-  $data_table->title = 'Fast feed';
-  $data_table->name = 'feeds_data_feed_fast';
-  $data_table->table_schema = array(
-    'fields' => array(
-      'feed_nid' => array(
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-      ),
-      'id' => array(
-        'type' => 'serial',
-        'size' => 'normal',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-      ),
-      'timestamp' => array(
-        'description' => 'The Unix timestamp for the data.',
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => FALSE,
-      ),
-      'title' => array(
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => FALSE,
-      ),
-      'description' => array(
-        'type' => 'text',
-        'not null' => FALSE,
-      ),
-      'url' => array(
-        'type' => 'text',
-        'not null' => FALSE,
-      ),
-      'guid' => array(
-        'type' => 'text',
-        'not null' => FALSE,
-      ),
-    ),
-    'indexes' => array(
-      'feed_nid' => array(
-        '0' => 'feed_nid',
-      ),
-      'id' => array(
-        '0' => 'id',
-      ),
-      'timestamp' => array(
-        '0' => 'timestamp',
-      ),
-      'url' => array(
-        '0' => array(
-          '0' => 'url',
-          '1' => 255,
-        ),
-      ),
-      'guid' => array(
-        '0' => array(
-          '0' => 'guid',
-          '1' => 255,
-        ),
-      ),
-    ),
-    'primary key' => array(
-      '0' => 'id',
-    ),
-  );
-  $data_table->meta = array(
-    'fields' => array(
-      'feed_nid' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field_numeric',
-        'views_filter_handler' => 'views_handler_filter_numeric',
-        'views_argument_handler' => 'views_handler_argument_numeric',
-        'views_sort_handler' => 'views_handler_sort',
-      ),
-      'id' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field_numeric',
-        'views_filter_handler' => 'views_handler_filter_numeric',
-        'views_argument_handler' => 'views_handler_argument_numeric',
-        'views_sort_handler' => 'views_handler_sort',
-      ),
-      'timestamp' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field_date',
-        'views_filter_handler' => 'views_handler_filter_date',
-        'views_argument_handler' => 'views_handler_argument_date',
-        'views_sort_handler' => 'views_handler_sort_date',
-      ),
-      'title' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field',
-        'views_filter_handler' => 'views_handler_filter_string',
-        'views_argument_handler' => 'views_handler_argument_string',
-        'views_sort_handler' => 'views_handler_sort',
-      ),
-      'description' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field',
-        'views_filter_handler' => 'views_handler_filter_string',
-        'views_argument_handler' => 'views_handler_argument',
-        'views_sort_handler' => 'views_handler_sort',
-      ),
-      'url' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field_url',
-        'views_filter_handler' => 'views_handler_filter_string',
-        'views_argument_handler' => 'views_handler_argument',
-        'views_sort_handler' => 'views_handler_sort',
-      ),
-      'guid' => array(
-        'label' => '',
-        'views_field_handler' => 'views_handler_field',
-        'views_filter_handler' => 'views_handler_filter_string',
-        'views_argument_handler' => 'views_handler_argument',
-        'views_sort_handler' => 'views_handler_sort',
-      ),
-    ),
-  );
-
-  $export['feeds_data_feed_fast'] = $data_table;
-  return $export;
-}
-
-/**
- * Helper to implementation of hook_feeds_importer_default().
- */
-function _feeds_defaults_feeds_importer_default() {
-  $export = array();
-  $feeds_importer = new stdClass;
-  $feeds_importer->disabled = TRUE; /* Edit this to true to make a default feeds_importer disabled initially */
-  $feeds_importer->api_version = 1;
-  $feeds_importer->id = 'feed';
-  $feeds_importer->config = array(
-    'name' => 'Feed',
-    'description' => 'Import RSS or Atom feeds, create nodes from feed items.',
-    'fetcher' => array(
-      'plugin_key' => 'FeedsHTTPFetcher',
-      'config' => array(
-        'auto_detect_feeds' => FALSE,
-      ),
-    ),
-    'parser' => array(
-      'plugin_key' => 'FeedsSyndicationParser',
-      'config' => array(),
-    ),
-    'processor' => array(
-      'plugin_key' => 'FeedsNodeProcessor',
-      'config' => array(
-        'content_type' => 'feed_item',
-        'update_existing' => 0,
-        'expire' => '-1',
-        'mappings' => array(
-          '0' => array(
-            'source' => 'title',
-            'target' => 'title',
-            'unique' => FALSE,
-          ),
-          '1' => array(
-            'source' => 'description',
-            'target' => 'body',
-            'unique' => FALSE,
-          ),
-          '2' => array(
-            'source' => 'timestamp',
-            'target' => 'created',
-            'unique' => FALSE,
-          ),
-          '3' => array(
-            'source' => 'url',
-            'target' => 'url',
-            'unique' => TRUE,
-          ),
-          '4' => array(
-            'source' => 'guid',
-            'target' => 'guid',
-            'unique' => TRUE,
-          ),
-        ),
-      ),
-    ),
-    'content_type' => 'feed',
-    'update' => 0,
-    'import_period' => '1800',
-    'expire_period' => 3600,
-    'import_on_create' => 1,
-  );
-
-  $export['feed'] = $feeds_importer;
-
-  // Expose a default configuration for Data if enabled.
-  if (module_exists('data')) {
-
-    $feeds_importer = new stdClass;
-    $feeds_importer->disabled = TRUE; /* Edit this to true to make a default feeds_importer disabled initially */
-    $feeds_importer->api_version = 1;
-    $feeds_importer->id = 'feed_fast';
-    $feeds_importer->config = array(
-      'name' => 'Fast feed',
-      'description' => 'Create light weight database records from feed items. Faster than aggregating nodes.',
-      'fetcher' => array(
-        'plugin_key' => 'FeedsHTTPFetcher',
-        'config' => array(
-          'auto_detect_feeds' => FALSE,
-        ),
-      ),
-      'parser' => array(
-        'plugin_key' => 'FeedsSyndicationParser',
-        'config' => array(),
-      ),
-      'processor' => array(
-        'plugin_key' => 'FeedsDataProcessor',
-        'config' => array(
-          'update_existing' => 0,
-          'expire' => '7257600',
-          'mappings' => array(
-            '0' => array(
-              'source' => 'title',
-              'target' => 'title',
-              'unique' => 0,
-            ),
-            '1' => array(
-              'source' => 'description',
-              'target' => 'description',
-              'unique' => 0,
-            ),
-            '2' => array(
-              'source' => 'url',
-              'target' => 'url',
-              'unique' => 1,
-            ),
-            '3' => array(
-              'source' => 'guid',
-              'target' => 'guid',
-              'unique' => 1,
-            ),
-          ),
-        ),
-      ),
-      'content_type' => 'feed_fast',
-      'update' => 0,
-      'import_period' => '1800',
-      'expire_period' => 3600,
-      'import_on_create' => 1,
-    );
-
-    $export['feed_fast'] = $feeds_importer;
-  }
-
-  $feeds_importer = new stdClass;
-  $feeds_importer->disabled = TRUE; /* Edit this to true to make a default feeds_importer disabled initially */
-  $feeds_importer->api_version = 1;
-  $feeds_importer->id = 'node';
-  $feeds_importer->config = array(
-    'name' => 'Node import',
-    'description' => 'Import nodes from CSV file.',
-    'fetcher' => array(
-      'plugin_key' => 'FeedsFileFetcher',
-      'config' => array(),
-    ),
-    'parser' => array(
-      'plugin_key' => 'FeedsCSVParser',
-      'config' => array(
-        'delimiter' => ',',
-      ),
-    ),
-    'processor' => array(
-      'plugin_key' => 'FeedsNodeProcessor',
-      'config' => array(
-        'content_type' => 'story',
-        'update_existing' => 1,
-        'expire' => '-1',
-        'mappings' => array(
-          '0' => array(
-            'source' => 'title',
-            'target' => 'title',
-            'unique' => FALSE,
-          ),
-          '1' => array(
-            'source' => 'body',
-            'target' => 'body',
-            'unique' => FALSE,
-          ),
-          '2' => array(
-            'source' => 'published',
-            'target' => 'created',
-            'unique' => FALSE,
-          ),
-          '3' => array(
-            'source' => 'guid',
-            'target' => 'guid',
-            'unique' => 1,
-          ),
-        ),
-      ),
-    ),
-    'content_type' => '',
-    'update' => 0,
-    'import_period' => '-1',
-    'expire_period' => 3600,
-    'import_on_create' => 1,
-  );
-
-  $export['node'] = $feeds_importer;
-  $feeds_importer = new stdClass;
-  $feeds_importer->disabled = TRUE; /* Edit this to true to make a default feeds_importer disabled initially */
-  $feeds_importer->api_version = 1;
-  $feeds_importer->id = 'opml';
-  $feeds_importer->config = array(
-    'name' => 'OPML import',
-    'description' => 'Import subscriptions from OPML files. Use together with "Feed" configuration.',
-    'fetcher' => array(
-      'plugin_key' => 'FeedsFileFetcher',
-      'config' => array(),
-    ),
-    'parser' => array(
-      'plugin_key' => 'FeedsOPMLParser',
-      'config' => array(),
-    ),
-    'processor' => array(
-      'plugin_key' => 'FeedsFeedNodeProcessor',
-      'config' => array(
-        'content_type' => 'feed',
-        'update_existing' => 0,
-        'mappings' => array(
-          '0' => array(
-            'source' => 'title',
-            'target' => 'title',
-            'unique' => FALSE,
-          ),
-          '1' => array(
-            'source' => 'xmlurl',
-            'target' => 'source',
-            'unique' => 1,
-          ),
-        ),
-      ),
-    ),
-    'content_type' => '',
-    'update' => 0,
-    'import_period' => '-1',
-    'expire_period' => 3600,
-    'import_on_create' => 1,
-  );
-
-  $export['opml'] = $feeds_importer;
-  $feeds_importer = new stdClass;
-  $feeds_importer->disabled = TRUE; /* Edit this to true to make a default feeds_importer disabled initially */
-  $feeds_importer->api_version = 1;
-  $feeds_importer->id = 'user';
-  $feeds_importer->config = array(
-    'name' => 'User import',
-    'description' => 'Import users from CSV file.',
-    'fetcher' => array(
-      'plugin_key' => 'FeedsFileFetcher',
-      'config' => array(),
-    ),
-    'parser' => array(
-      'plugin_key' => 'FeedsCSVParser',
-      'config' => array(
-        'delimiter' => ',',
-      ),
-    ),
-    'processor' => array(
-      'plugin_key' => 'FeedsUserProcessor',
-      'config' => array(
-        'roles' => array(),
-        'update_existing' => FALSE,
-        'status' => 1,
-        'mappings' => array(
-          '0' => array(
-            'source' => 'name',
-            'target' => 'name',
-            'unique' => 0,
-          ),
-          '1' => array(
-            'source' => 'mail',
-            'target' => 'mail',
-            'unique' => 1,
-          ),
-          '2' => array(
-            'source' => 'created',
-            'target' => 'created',
-            'unique' => FALSE,
-          ),
-        ),
-      ),
-    ),
-    'content_type' => '',
-    'update' => 0,
-    'import_period' => '-1',
-    'expire_period' => 3600,
-    'import_on_create' => 1,
-  );
-
-  $export['user'] = $feeds_importer;
-  return $export;
-}
diff --git a/feeds_defaults/feeds_defaults.features.inc b/feeds_defaults/feeds_defaults.features.inc
deleted file mode 100644
index 2247f14f..00000000
--- a/feeds_defaults/feeds_defaults.features.inc
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-// $Id$
-
-/**
- * @file
- * Default hook definitions. This code is generated with Features module but it
- * has been tweaked manually. Do not attempt to reexport.
- */
-
-/**
- * Implementation of hook_ctools_plugin_api().
- */
-function feeds_defaults_ctools_plugin_api() {
-  module_load_include('inc', 'feeds_defaults', 'feeds_defaults.defaults');
-  $args = func_get_args();
-  return call_user_func_array('_feeds_defaults_ctools_plugin_api', $args);
-}
-
-/**
- * Implementation of hook_data_default().
- */
-function feeds_defaults_data_default() {
-  module_load_include('inc', 'feeds_defaults', 'feeds_defaults.defaults');
-  $args = func_get_args();
-  return call_user_func_array('_feeds_defaults_data_default', $args);
-}
-
-/**
- * Implementation of hook_feeds_importer_default().
- */
-function feeds_defaults_feeds_importer_default() {
-  module_load_include('inc', 'feeds_defaults', 'feeds_defaults.defaults');
-  $args = func_get_args();
-  return call_user_func_array('_feeds_defaults_feeds_importer_default', $args);
-}
diff --git a/feeds_defaults/feeds_defaults.info b/feeds_defaults/feeds_defaults.info
deleted file mode 100644
index bd333032..00000000
--- a/feeds_defaults/feeds_defaults.info
+++ /dev/null
@@ -1,8 +0,0 @@
-; $Id$
-core = "6.x"
-name = "Feeds Defaults"
-package = "Feeds"
-description = "Get started: useful default configurations for Feeds: RSS/Atom aggregation, OPML import, node import and user import."
-project = "Feeds"
-dependencies[] = "feeds"
-php = 5.2
diff --git a/feeds_defaults/feeds_defaults.install b/feeds_defaults/feeds_defaults.install
deleted file mode 100644
index 93a10600..00000000
--- a/feeds_defaults/feeds_defaults.install
+++ /dev/null
@@ -1,35 +0,0 @@
-<?php
-// $Id$
-
-/**
- * @file
- * Install hooks.
- */
-
-/**
- * Implementation of hook_schema().
- */
-function feeds_defaults_schema() {
-  // Install data tables.
-  include_once('feeds_defaults.features.inc');
-  $tables = feeds_defaults_data_default();
-  $schema = array();
-  foreach ($tables as $name => $table) {
-    $schema[$name] = $table->table_schema;
-  }
-  return $schema;
-}
-
-/**
- * Implementation of hook_install().
- */
-function feeds_defaults_install() {
-  drupal_install_schema('feeds_defaults');
-}
-
-/**
- * Implementation of hook_uninstall();
- */
-function feeds_defaults_uninstall() {
-  drupal_uninstall_schema('feeds_defaults');
-}
diff --git a/feeds_defaults/feeds_defaults.module b/feeds_defaults/feeds_defaults.module
deleted file mode 100644
index cf03317b..00000000
--- a/feeds_defaults/feeds_defaults.module
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-// $Id$
-
-/**
- * @file
- * Default importer configurations for Feeds module.
- */
-
-require_once(dirname(__FILE__) .'/feeds_defaults.features.inc');
-
-/**
- * Implementation of hook_node_info().
- */
-function feeds_defaults_node_info() {
-  $items = array();
-  if (in_array('feed', feeds_enabled_importers())) {
-    $items['feed'] = array(
-      'name' => t('Feed'),
-      'module' => 'node',
-      'description' => t('Subscribe to RSS or Atom feeds. Creates nodes of the content type "Feed item" from feed content.'),
-      'has_title' => '1',
-      'title_label' => t('Title'),
-      'has_body' => '1',
-      'body_label' => t('Body'),
-      'locked' => TRUE,
-    );
-    $items['feed_item'] = array(
-      'name' => t('Feed item'),
-      'module' => 'node',
-      'description' => t('This content type is being used for automatically aggregated content from feeds.'),
-      'has_title' => '1',
-      'title_label' => t('Title'),
-      'has_body' => '1',
-      'body_label' => t('Body'),
-      'locked' => TRUE,
-    );
-  }
-  if (in_array('feed_fast', feeds_enabled_importers())) {
-    $items['feed_fast'] = array(
-      'name' => t('Fast feed'),
-      'module' => 'node',
-      'description' => t('Subscribe to RSS or Atom feeds. Create light weight database records from feed content.'),
-      'has_title' => '1',
-      'title_label' => t('Title'),
-      'has_body' => '1',
-      'body_label' => t('Body'),
-      'locked' => TRUE,
-    );
-  }
-  return $items;
-}
diff --git a/feeds_defaults/tests/feeds_defaults.test b/feeds_defaults/tests/feeds_defaults.test
deleted file mode 100644
index 5f7aac74..00000000
--- a/feeds_defaults/tests/feeds_defaults.test
+++ /dev/null
@@ -1,469 +0,0 @@
-<?php
-// $Id$
-
-/**
- * @file
- * Tests for default configurations.
- */
-
-// Require FeedsWebTestCase class definition.
-require_once(dirname(__FILE__) .'/../../tests/feeds.test.inc');
-
-/**
- * Base class for default tests.
- */
-class FeedsDefaultsTestCase extends FeedsWebTestCase {
-
-  /**
-   * Enable a default configuration and verify it.
-   */
-  public function enable($ids) {
-    if (is_string($ids)) {
-      $ids = array($ids);
-    }
-    $edit = array();
-    foreach ($ids as $id) {
-      $edit[$id] = TRUE;
-    }
-    $this->drupalPost('admin/build/feeds', $edit, 'Save');
-    foreach ($ids as $id) {
-      $this->assertRaw('admin/build/feeds/edit/'. $id .'">Override', 'Enabled '. $id);
-    }
-  }
-
-  /**
-   * Disable a default configuration and verify it.
-   */
-  public function disable($ids) {
-    if (is_string($ids)) {
-      $ids = array($ids);
-    }
-    $edit = array();
-    foreach ($ids as $id) {
-      $edit[$id] = FALSE;
-    }
-    $this->drupalPost('admin/build/feeds', $edit, 'Save');
-    foreach ($ids as $id) {
-      $this->assertNoRaw('admin/build/feeds/edit/'. $id .'">Override', 'Disabled '. $id);
-    }
-  }
-}
-
-/**
- * Test Feed configuration.
- */
-class FeedsDefaultsFeedTestCase extends FeedsDefaultsTestCase {
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_defaults');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-  }
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Defaults: Feed'),
-      'description' => t('Test "Feed" default configuration.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-    $this->enable('feed');
-    $nid = $this->createFeedNode('feed', NULL, '', 'feed');
-
-    // Assert results.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'feed_item'"));
-    $this->assertEqual($count, 10, 'Found the correct number of feed item nodes in database.');
-
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 10, 'Found the correct number of records in feeds_node_item.');
-
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Open Atrium Translation Workflow: Two Way Translation Updates'"));
-    $this->assertEqual($count, 1, 'Found title.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Week in DC Tech: October 5th Edition'"));
-    $this->assertEqual($count, 1, 'Found title.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Integrating the Siteminder Access System in an Open Atrium-based Intranet'"));
-    $this->assertEqual($count, 1, 'Found title.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Scaling the Open Atrium UI'"));
-    $this->assertEqual($count, 1, 'Found title.');
-
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE url = 'http://developmentseed.org/blog/2009/oct/06/open-atrium-translation-workflow-two-way-updating'"));
-    $this->assertEqual($count, 1, 'Found feed_node_item record.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE url = 'http://developmentseed.org/blog/2009/oct/05/week-dc-tech-october-5th-edition'"));
-    $this->assertEqual($count, 1, 'Found feed_node_item record.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE guid = '974 at http://developmentseed.org'"));
-    $this->assertEqual($count, 1, 'Found feed_node_item record.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE guid = '970 at http://developmentseed.org'"));
-    $this->assertEqual($count, 1, 'Found feed_node_item record.');
-
-    // Remove all items
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 10 nodes.');
-
-    // Import again.
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('Created 10 Feed item nodes.');
-
-    // Delete and assert all items gone.
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'feed_item'"));
-    $this->assertEqual($count, 0, 'Found the correct number of feed item nodes in database.');
-
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 0, 'Found the correct number of records in feeds_node_item.');
-
-    // Create a batch of nodes.
-    $this->createFeedNodes('feed', 10, 'feed');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'feed_item'"));
-    $this->assertEqual($count, 100, 'Imported 100 nodes.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 100, 'Found 100 records in feeds_node_item.');
-
-    // Disable the configuration.
-    $this->disable('feed');
-    $this->drupalGet('node/add');
-    $this->assertNoRaw('node/add/feed');
-    $this->assertNoText('node/add/feed-item');
-  }
-}
-
-/**
- * Test Feed fast configuration.
- */
-class FeedsDefaultsFastFeedTestCase extends FeedsDefaultsTestCase {
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_defaults', 'data', 'data_ui', 'views', 'views_ui');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes', 'administer data tables',
-        )
-      )
-    );
-  }
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Defaults: Fast feed'),
-      'description' => t('Test "Fast feed" default configuration <strong>Requires Data and Views.</strong>'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-
-    // Enable configuration and assert status.
-    $this->enable('feed_fast');
-    $this->drupalGet('admin/build/data');
-    $this->assertText('feeds_data_feed_fast');
-    $this->drupalGet('admin/content/data/view/feeds_data_feed_fast');
-    $this->assertText('Fast feed');
-    $this->assertText('There is no data in this table.');
-
-    // Create feed node.
-    $nid = $this->createFeedNode('feed_fast', NULL, '', 'feed_fast');
-    $this->assertText('Created 10 items.');
-
-    // Verify presence of aggregated items.
-    $this->drupalGet('admin/content/data/view/feeds_data_feed_fast');
-    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
-    $this->assertText('n a word, nothing. There has been a major improvement on this front. Now your translation');
-    $this->assertLink('http://developmentseed.org/blog/2009/oct/06/open-atrium-translation-workflow-two-way-updating');
-
-    // Delete and re import.
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 10 items.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
-    $this->assertEqual($count, 0, 'Found correct number of items.');
-
-    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 0 items.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
-    $this->assertEqual($count, 0, 'Found correct number of items.');
-
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('Created 10 items.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
-    $this->assertEqual($count, 10, 'Found correct number of items.');
-
-    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
-    $this->assertText('There are no new items.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
-    $this->assertEqual($count, 10, 'Found correct number of items.');
-
-    // Disable.
-    $this->disable('feed_fast');
-    $this->drupalGet('node/add');
-    $this->assertNoRaw('node/add/feed-fast');
-  }
-}
-
-/**
- * Test Node import configuration.
- */
-class FeedsDefaultsNodeTestCase extends FeedsDefaultsTestCase {
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_defaults');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-  }
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Defaults: Node import'),
-      'description' => t('Test "Node import" default configuration.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-    $this->enable('node');
-
-    // Import file.
-    $this->importFile('node', $this->absolutePath() .'/tests/feeds/nodes.csv');
-
-    // Assert returning page.
-    $this->assertText('Created 8 Story nodes.');
-    $this->assertText('Import CSV files with one or more of these columns: title, body, published, guid.');
-    $this->assertText('Column guid is mandatory and considered unique: only one item per guid value will be created.');
-    $this->assertRaw('feeds/nodes.csv');
-
-    // Assert created nodes.
-    $this->drupalGet('node');
-    $this->assertText('Typi non habent');
-    $this->assertText('Eodem modo typi');
-    $this->assertText('Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.');
-    $this->assertText('Lorem ipsum');
-    $this->assertText('Ut wisi enim ad minim veniam');
-    $this->assertText('1976');
-    // Nam liber tempor has the same GUID as Lorem ipsum.
-    $this->assertNoText('Nam liber tempor');
-
-    // Click through to one node.
-    $this->clickLink('Lorem ipsum');
-    $this->assertText('Lorem ipsum');
-    $this->assertText('Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.');
-    $this->assertText('Anonymous');
-
-    // Assert DB status as is and again after an additional import.
-    for ($i = 0; $i < 2; $i++) {
-      $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-      $this->assertEqual($count, 8, 'Found correct number of items.');
-      $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1 AND uid = 0"));
-      $this->assertEqual($count, 8, 'Found correct number of items.');
-      // Do not filter on type intentionally. There shouldn't be more than 8 nodes total.
-      $count = db_result(db_query("SELECT COUNT(*) FROM {node_revisions}"));
-      $this->assertEqual($count, 8, 'Found correct number of items.');
-
-      // Import again. Feeds only updates items that haven't changed. However,
-      // there are 2 different items with the same GUID in nodes.csv.
-      // Therefore, feeds will show updates to 2 nodes.
-      $this->drupalPost('import/node/import', array(), 'Import');
-      $this->assertText('Updated 2 Story nodes.');
-    }
-
-    // Remove all nodes.
-    $this->drupalPost('import/node/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 8 nodes.');
-
-    // Import once again.
-    $this->drupalPost('import/node/import', array(), 'Import');
-    $this->assertText('Created 8 Story nodes.');
-
-    // Import a similar file with changes in 4 records. Feeds should report 6
-    // Updated story nodes (4 changed records, 2 records sharing a GUID
-    // subsequently being updated).
-    $this->importFile('node', $this->absolutePath() .'/tests/feeds/nodes_changes.csv');
-    $this->assertText('Updated 6 Story nodes.');
-
-    // Import a larger file with more records.
-    $this->importFile('node', $this->absolutePath() .'/tests/feeds/many_nodes.csv');
-    $this->assertText('Created 71 Story nodes.');
-
-    // Remove all nodes.
-    $this->drupalPost('import/node/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 79 nodes.');
-
-    // Import once again.
-    $this->drupalPost('import/node/import', array(), 'Import');
-    $this->assertText('Created 79 Story nodes.');
-
-    // Disable, nodes should be still present.
-    $this->disable('node');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
-    $this->assertEqual($count, 79, 'Found correct number of items.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1 AND uid = 0"));
-    $this->assertEqual($count, 79, 'Found correct number of items.');
-    // Do not filter on type intentionally. There shouldn't be more than 8 nodes total.
-    $count = db_result(db_query("SELECT COUNT(*) FROM {node_revisions}"));
-    $this->assertEqual($count, 79, 'Found correct number of items.');
-
-    // Import a tab separated file.
-    $this->enable('node');
-    $this->drupalPost('import/node/delete-items', array(), 'Delete');
-    $edit = array(
-      'files[feeds]' => $this->absolutePath() .'/tests/feeds/nodes.tsv',
-      'feeds[FeedsCSVParser][delimiter]' => "TAB",
-    );
-    $this->drupalPost('import/node', $edit, 'Import');
-    $this->assertText('Created 8 Story nodes.');
-
-    // Disable before exiting test.
-    $this->disable('node');
-  }
-}
-
-/**
- * Test OPML import configuration.
- */
-class FeedsDefaultsOPMLTestCase extends FeedsDefaultsTestCase {
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_defaults');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer nodes',
-        )
-      )
-    );
-  }
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Defaults: OPML import'),
-      'description' => t('Test "OPML import" default configuration.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-    $this->enable('feed');
-    $this->enable('opml');
-
-    // Import OPML and assert.
-    $file = $this->generateOPML();
-    $this->importFile('opml', $file);
-    $this->assertText('Created 3 feed nodes.');
-    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_source}"));
-    $this->assertEqual($count, 4, 'Found correct number of items.');
-
-    // Import a feed and then delete all items from it.
-    $this->drupalPost('node/1/import', array(), 'Import');
-    $this->assertText('Created 10 Feed item nodes.');
-    $this->drupalPost('node/1/delete-items', array(), 'Delete');
-    $this->assertText('Deleted 10 nodes.');
-
-    // Disable.
-    $this->disable('feed');
-    $this->disable('opml');
-  }
-}
-
-/**
- * Test User import configuration.
- */
-class FeedsDefaultsUserTestCase extends FeedsDefaultsTestCase {
-
-  /**
-   * Set up test.
-   */
-  public function setUp() {
-    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_defaults');
-
-    $this->drupalLogin(
-      $this->drupalCreateUser(
-        array(
-          'administer feeds', 'administer users',
-        )
-      )
-    );
-  }
-
-  /**
-   * Describe this test.
-   */
-  public function getInfo() {
-    return array(
-      'name' => t('Defaults: User import'),
-      'description' => t('Test "User import" default configuration.'),
-      'group' => t('Feeds'),
-    );
-  }
-
-  /**
-   * Run tests.
-   */
-  public function test() {
-    $this->enable('user');
-
-    // Import CSV file.
-    $this->importFile('user', $this->absolutePath() .'/tests/feeds/users.csv');
-
-    // Assert result.
-    $this->assertText('Created 4 users.');
-    // 1 user has an invalid email address.
-    $this->assertText('There was 1 user that could not be imported because either their name or their email was empty or not valid. Check import data and mapping settings on User processor.');
-    $this->drupalGet('admin/user/user');
-    $this->assertText('Morticia');
-    $this->assertText('Fester');
-    $this->assertText('Gomez');
-    $this->assertText('Pugsley');
-
-    $this->disable('user');
-  }
-}
diff --git a/feeds_fast_news/feeds_fast_news.data_default.inc b/feeds_fast_news/feeds_fast_news.data_default.inc
new file mode 100644
index 00000000..758b93d2
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.data_default.inc
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * Implementation of hook_data_default().
+ */
+function feeds_fast_news_data_default() {
+  $export = array();
+  $data_table = new stdClass;
+  $data_table->disabled = FALSE; /* Edit this to true to make a default data_table disabled initially */
+  $data_table->api_version = 1;
+  $data_table->title = 'Fast feed';
+  $data_table->name = 'feeds_data_feed_fast';
+  $data_table->table_schema = array(
+    'fields' => array(
+      'feed_nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'id' => array(
+        'type' => 'serial',
+        'size' => 'normal',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'timestamp' => array(
+        'description' => 'The Unix timestamp for the data.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => FALSE,
+      ),
+      'title' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => FALSE,
+      ),
+      'description' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+      'url' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+      'guid' => array(
+        'type' => 'text',
+        'not null' => FALSE,
+      ),
+    ),
+    'indexes' => array(
+      'feed_nid' => array(
+        '0' => 'feed_nid',
+      ),
+      'id' => array(
+        '0' => 'id',
+      ),
+      'timestamp' => array(
+        '0' => 'timestamp',
+      ),
+      'url' => array(
+        '0' => array(
+          '0' => 'url',
+          '1' => 255,
+        ),
+      ),
+      'guid' => array(
+        '0' => array(
+          '0' => 'guid',
+          '1' => 255,
+        ),
+      ),
+    ),
+    'primary key' => array(
+      '0' => 'id',
+    ),
+  );
+  $data_table->meta = array(
+    'fields' => array(
+      'feed_nid' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field_numeric',
+        'views_filter_handler' => 'views_handler_filter_numeric',
+        'views_argument_handler' => 'views_handler_argument_numeric',
+        'views_sort_handler' => 'views_handler_sort',
+      ),
+      'id' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field_numeric',
+        'views_filter_handler' => 'views_handler_filter_numeric',
+        'views_argument_handler' => 'views_handler_argument_numeric',
+        'views_sort_handler' => 'views_handler_sort',
+      ),
+      'timestamp' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field_date',
+        'views_filter_handler' => 'views_handler_filter_date',
+        'views_argument_handler' => 'views_handler_argument_date',
+        'views_sort_handler' => 'views_handler_sort_date',
+      ),
+      'title' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field',
+        'views_filter_handler' => 'views_handler_filter_string',
+        'views_argument_handler' => 'views_handler_argument_string',
+        'views_sort_handler' => 'views_handler_sort',
+      ),
+      'description' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field',
+        'views_filter_handler' => 'views_handler_filter_string',
+        'views_argument_handler' => 'views_handler_argument',
+        'views_sort_handler' => 'views_handler_sort',
+      ),
+      'url' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field_url',
+        'views_filter_handler' => 'views_handler_filter_string',
+        'views_argument_handler' => 'views_handler_argument',
+        'views_sort_handler' => 'views_handler_sort',
+      ),
+      'guid' => array(
+        'label' => '',
+        'views_field_handler' => 'views_handler_field',
+        'views_filter_handler' => 'views_handler_filter_string',
+        'views_argument_handler' => 'views_handler_argument',
+        'views_sort_handler' => 'views_handler_sort',
+      ),
+    ),
+  );
+
+  $export['feeds_data_feed_fast'] = $data_table;
+  return $export;
+}
diff --git a/feeds_fast_news/feeds_fast_news.features.inc b/feeds_fast_news/feeds_fast_news.features.inc
new file mode 100644
index 00000000..709063ff
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.features.inc
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * Implementation of hook_ctools_plugin_api().
+ */
+function feeds_fast_news_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "data" && $api == "data_default") {
+    return array("version" => 1);
+  }
+  elseif ($module == "data" && $api == "data_table") {
+    return array("version" => 1);
+  }
+  elseif ($module == "feeds" && $api == "feeds_importer_default") {
+    return array("version" => 1);
+  }
+}
+
+/**
+ * Implementation of hook_node_info().
+ */
+function feeds_fast_news_node_info() {
+  $items = array(
+    'feed_fast' => array(
+      'name' => t('Fast feed'),
+      'module' => 'node',
+      'description' => t('Subscribe to RSS or Atom feeds. Create light weight database records from feed content.'),
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'has_body' => '1',
+      'body_label' => t('Body'),
+      'min_word_count' => '0',
+      'help' => '',
+    ),
+  );
+  return $items;
+}
diff --git a/feeds_fast_news/feeds_fast_news.feeds_importer_default.inc b/feeds_fast_news/feeds_fast_news.feeds_importer_default.inc
new file mode 100644
index 00000000..023cfd02
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.feeds_importer_default.inc
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * Implementation of hook_feeds_importer_default().
+ */
+function feeds_fast_news_feeds_importer_default() {
+  $export = array();
+  $feeds_importer = new stdClass;
+  $feeds_importer->disabled = FALSE; /* Edit this to true to make a default feeds_importer disabled initially */
+  $feeds_importer->api_version = 1;
+  $feeds_importer->id = 'feed_fast';
+  $feeds_importer->config = array(
+    'name' => 'Fast feed',
+    'description' => 'Create light weight database records from feed items. Faster than aggregating nodes.',
+    'fetcher' => array(
+      'plugin_key' => 'FeedsHTTPFetcher',
+      'config' => array(
+        'auto_detect_feeds' => FALSE,
+        'use_pubsubhubbub' => FALSE,
+        'designated_hub' => '',
+      ),
+    ),
+    'parser' => array(
+      'plugin_key' => 'FeedsSyndicationParser',
+      'config' => array(),
+    ),
+    'processor' => array(
+      'plugin_key' => 'FeedsDataProcessor',
+      'config' => array(
+        'update_existing' => 0,
+        'expire' => '7257600',
+        'mappings' => array(
+          '0' => array(
+            'source' => 'title',
+            'target' => 'title',
+            'unique' => 0,
+          ),
+          '1' => array(
+            'source' => 'description',
+            'target' => 'description',
+            'unique' => 0,
+          ),
+          '2' => array(
+            'source' => 'url',
+            'target' => 'url',
+            'unique' => 1,
+          ),
+          '3' => array(
+            'source' => 'guid',
+            'target' => 'guid',
+            'unique' => 1,
+          ),
+        ),
+      ),
+    ),
+    'content_type' => 'feed_fast',
+    'update' => 0,
+    'import_period' => '1800',
+    'expire_period' => 3600,
+    'import_on_create' => 1,
+  );
+
+  $export['feed_fast'] = $feeds_importer;
+  return $export;
+}
diff --git a/feeds_fast_news/feeds_fast_news.info b/feeds_fast_news/feeds_fast_news.info
new file mode 100644
index 00000000..70547f87
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.info
@@ -0,0 +1,13 @@
+core = "6.x"
+dependencies[] = "data"
+dependencies[] = "feeds"
+description = "A fast news aggregator built with feeds, creates flat database records from imported feed items."
+features[ctools][] = "data:data_default:1"
+features[ctools][] = "data:data_table:1"
+features[ctools][] = "feeds:feeds_importer_default:1"
+features[data_tables][] = "feeds_data_feed_fast"
+features[feeds_importer][] = "feed_fast"
+features[node][] = "feed_fast"
+name = "Feeds Fast News"
+package = "Feeds"
+project = "Feeds"
diff --git a/feeds_fast_news/feeds_fast_news.install b/feeds_fast_news/feeds_fast_news.install
new file mode 100644
index 00000000..ba78a0ab
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.install
@@ -0,0 +1,46 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Install hooks.
+ */
+
+/**
+ * Implementation of hook_schema().
+ */
+function feeds_fast_news_schema() {
+  // Install data tables.
+  include_once('feeds_fast_news.data_default.inc');
+  $tables = feeds_fast_news_data_default();
+  $schema = array();
+  foreach ($tables as $name => $table) {
+    $schema[$name] = $table->table_schema;
+  }
+  return $schema;
+}
+
+/**
+ * Implementation of hook_install().
+ */
+function feeds_fast_news_install() {
+  // We are replacing feeds_defaults module, taking over its table.
+  // Hence we cannot use drupal_install_schema('feeds_fast_news');
+  $schema = drupal_get_schema_unprocessed('feeds_fast_news');
+  _drupal_initialize_schema('feeds_fast_news', $schema);
+
+  $ret = array();
+  foreach ($schema as $name => $table) {
+    // Check whether table exists.
+    if (!db_table_exists($name)) {
+      db_create_table($ret, $name, $table);
+    }
+  }
+}
+
+/**
+ * Implementation of hook_uninstall();
+ */
+function feeds_defaults_uninstall() {
+  drupal_uninstall_schema('feeds_fast_news');
+}
diff --git a/feeds_fast_news/feeds_fast_news.module b/feeds_fast_news/feeds_fast_news.module
new file mode 100644
index 00000000..ead9b390
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.module
@@ -0,0 +1,3 @@
+<?php
+
+include_once('feeds_fast_news.features.inc');
diff --git a/feeds_fast_news/feeds_fast_news.test b/feeds_fast_news/feeds_fast_news.test
new file mode 100644
index 00000000..66b30424
--- /dev/null
+++ b/feeds_fast_news/feeds_fast_news.test
@@ -0,0 +1,86 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for feeds_fast_news feature.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/../tests/feeds.test.inc');
+
+/**
+ * Test Feed fast configuration.
+ */
+class FeedsExamplesFastFeedTestCase extends FeedsWebTestCase {
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'features', 'feeds_fast_news', 'data', 'data_ui', 'views', 'views_ui');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes', 'administer data tables',
+        )
+      )
+    );
+  }
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Feature: Fast feed'),
+      'description' => t('Test "Fast feed" default configuration <strong>Requires Data, Features and Views.</strong>'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+
+    // Enable configuration and assert status.
+    $this->drupalGet('admin/build/data');
+    $this->assertText('feeds_data_feed_fast');
+    $this->drupalGet('admin/content/data/view/feeds_data_feed_fast');
+    $this->assertText('Fast feed');
+    $this->assertText('There is no data in this table.');
+
+    // Create feed node.
+    $nid = $this->createFeedNode('feed_fast', NULL, '', 'feed_fast');
+    $this->assertText('Created 10 items.');
+
+    // Verify presence of aggregated items.
+    $this->drupalGet('admin/content/data/view/feeds_data_feed_fast');
+    $this->assertText('Open Atrium Translation Workflow: Two Way Translation Updates');
+    $this->assertText('n a word, nothing. There has been a major improvement on this front. Now your translation');
+    $this->assertLink('http://developmentseed.org/blog/2009/oct/06/open-atrium-translation-workflow-two-way-updating');
+
+    // Delete and re import.
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 10 items.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
+    $this->assertEqual($count, 0, 'Found correct number of items.');
+
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 0 items.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
+    $this->assertEqual($count, 0, 'Found correct number of items.');
+
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('Created 10 items.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
+    $this->assertEqual($count, 10, 'Found correct number of items.');
+
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('There are no new items.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_data_feed_fast}"));
+    $this->assertEqual($count, 10, 'Found correct number of items.');
+  }
+}
diff --git a/feeds_import/feeds_import.features.inc b/feeds_import/feeds_import.features.inc
new file mode 100644
index 00000000..fd84a3af
--- /dev/null
+++ b/feeds_import/feeds_import.features.inc
@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * Implementation of hook_ctools_plugin_api().
+ */
+function feeds_import_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "feeds" && $api == "feeds_importer_default") {
+    return array("version" => 1);
+  }
+}
diff --git a/feeds_import/feeds_import.feeds_importer_default.inc b/feeds_import/feeds_import.feeds_importer_default.inc
new file mode 100644
index 00000000..8e4fd92f
--- /dev/null
+++ b/feeds_import/feeds_import.feeds_importer_default.inc
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * Implementation of hook_feeds_importer_default().
+ */
+function feeds_import_feeds_importer_default() {
+  $export = array();
+  $feeds_importer = new stdClass;
+  $feeds_importer->disabled = FALSE; /* Edit this to true to make a default feeds_importer disabled initially */
+  $feeds_importer->api_version = 1;
+  $feeds_importer->id = 'node';
+  $feeds_importer->config = array(
+    'name' => 'Node import',
+    'description' => 'Import nodes from CSV file.',
+    'fetcher' => array(
+      'plugin_key' => 'FeedsFileFetcher',
+      'config' => array(
+        'direct' => FALSE,
+      ),
+    ),
+    'parser' => array(
+      'plugin_key' => 'FeedsCSVParser',
+      'config' => array(
+        'delimiter' => ',',
+      ),
+    ),
+    'processor' => array(
+      'plugin_key' => 'FeedsNodeProcessor',
+      'config' => array(
+        'content_type' => 'story',
+        'update_existing' => 1,
+        'expire' => '-1',
+        'mappings' => array(
+          '0' => array(
+            'source' => 'title',
+            'target' => 'title',
+            'unique' => FALSE,
+          ),
+          '1' => array(
+            'source' => 'body',
+            'target' => 'body',
+            'unique' => FALSE,
+          ),
+          '2' => array(
+            'source' => 'published',
+            'target' => 'created',
+            'unique' => FALSE,
+          ),
+          '3' => array(
+            'source' => 'guid',
+            'target' => 'guid',
+            'unique' => 1,
+          ),
+        ),
+        'input_format' => 0,
+        'author' => 0,
+      ),
+    ),
+    'content_type' => '',
+    'update' => 0,
+    'import_period' => '-1',
+    'expire_period' => 3600,
+    'import_on_create' => 1,
+  );
+
+  $export['node'] = $feeds_importer;
+  $feeds_importer = new stdClass;
+  $feeds_importer->disabled = FALSE; /* Edit this to true to make a default feeds_importer disabled initially */
+  $feeds_importer->api_version = 1;
+  $feeds_importer->id = 'user';
+  $feeds_importer->config = array(
+    'name' => 'User import',
+    'description' => 'Import users from CSV file.',
+    'fetcher' => array(
+      'plugin_key' => 'FeedsFileFetcher',
+      'config' => array(
+        'direct' => FALSE,
+      ),
+    ),
+    'parser' => array(
+      'plugin_key' => 'FeedsCSVParser',
+      'config' => array(
+        'delimiter' => ',',
+      ),
+    ),
+    'processor' => array(
+      'plugin_key' => 'FeedsUserProcessor',
+      'config' => array(
+        'roles' => array(),
+        'update_existing' => FALSE,
+        'status' => 1,
+        'mappings' => array(
+          '0' => array(
+            'source' => 'name',
+            'target' => 'name',
+            'unique' => 0,
+          ),
+          '1' => array(
+            'source' => 'mail',
+            'target' => 'mail',
+            'unique' => 1,
+          ),
+          '2' => array(
+            'source' => 'created',
+            'target' => 'created',
+            'unique' => FALSE,
+          ),
+        ),
+      ),
+    ),
+    'content_type' => '',
+    'update' => 0,
+    'import_period' => '-1',
+    'expire_period' => 3600,
+    'import_on_create' => 1,
+  );
+
+  $export['user'] = $feeds_importer;
+  return $export;
+}
diff --git a/feeds_import/feeds_import.info b/feeds_import/feeds_import.info
new file mode 100644
index 00000000..448296d1
--- /dev/null
+++ b/feeds_import/feeds_import.info
@@ -0,0 +1,9 @@
+core = "6.x"
+dependencies[] = "feeds"
+description = "An example of a node importer and a user importer."
+features[ctools][] = "feeds:feeds_importer_default:1"
+features[feeds_importer][] = "node"
+features[feeds_importer][] = "user"
+name = "Feeds Import"
+package = "Feeds"
+project = "Feeds"
diff --git a/feeds_import/feeds_import.module b/feeds_import/feeds_import.module
new file mode 100644
index 00000000..a7b47532
--- /dev/null
+++ b/feeds_import/feeds_import.module
@@ -0,0 +1,3 @@
+<?php
+
+include_once('feeds_import.features.inc');
diff --git a/feeds_import/feeds_import.test b/feeds_import/feeds_import.test
new file mode 100644
index 00000000..59902a53
--- /dev/null
+++ b/feeds_import/feeds_import.test
@@ -0,0 +1,175 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for feeds_import feature.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/../tests/feeds.test.inc');
+
+/**
+ * Test Node import configuration.
+ */
+class FeedsExamplesNodeTestCase extends FeedsWebTestCase {
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_import');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+  }
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Feature: Node import'),
+      'description' => t('Test "Node import" default configuration.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+    // Import file.
+    $this->importFile('node', $this->absolutePath() .'/tests/feeds/nodes.csv');
+
+    // Assert returning page.
+    $this->assertText('Created 8 Story nodes.');
+    $this->assertText('Import CSV files with one or more of these columns: title, body, published, guid.');
+    $this->assertText('Column guid is mandatory and considered unique: only one item per guid value will be created.');
+    $this->assertRaw('feeds/nodes.csv');
+
+    // Assert created nodes.
+    $this->drupalGet('node');
+    $this->assertText('Typi non habent');
+    $this->assertText('Eodem modo typi');
+    $this->assertText('Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.');
+    $this->assertText('Lorem ipsum');
+    $this->assertText('Ut wisi enim ad minim veniam');
+    $this->assertText('1976');
+    // Nam liber tempor has the same GUID as Lorem ipsum.
+    $this->assertNoText('Nam liber tempor');
+
+    // Click through to one node.
+    $this->clickLink('Lorem ipsum');
+    $this->assertText('Lorem ipsum');
+    $this->assertText('Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.');
+    $this->assertText('Anonymous');
+
+    // Assert DB status as is and again after an additional import.
+    for ($i = 0; $i < 2; $i++) {
+      $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+      $this->assertEqual($count, 8, 'Found correct number of items.');
+      $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'story' AND status = 1 AND uid = 0"));
+      $this->assertEqual($count, 8, 'Found correct number of items.');
+      // Do not filter on type intentionally. There shouldn't be more than 8 nodes total.
+      $count = db_result(db_query("SELECT COUNT(*) FROM {node_revisions}"));
+      $this->assertEqual($count, 8, 'Found correct number of items.');
+
+      // Import again. Feeds only updates items that haven't changed. However,
+      // there are 2 different items with the same GUID in nodes.csv.
+      // Therefore, feeds will show updates to 2 nodes.
+      $this->drupalPost('import/node/import', array(), 'Import');
+      $this->assertText('Updated 2 Story nodes.');
+    }
+
+    // Remove all nodes.
+    $this->drupalPost('import/node/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 8 nodes.');
+
+    // Import once again.
+    $this->drupalPost('import/node/import', array(), 'Import');
+    $this->assertText('Created 8 Story nodes.');
+
+    // Import a similar file with changes in 4 records. Feeds should report 6
+    // Updated story nodes (4 changed records, 2 records sharing a GUID
+    // subsequently being updated).
+    $this->importFile('node', $this->absolutePath() .'/tests/feeds/nodes_changes.csv');
+    $this->assertText('Updated 6 Story nodes.');
+
+    // Import a larger file with more records.
+    $this->importFile('node', $this->absolutePath() .'/tests/feeds/many_nodes.csv');
+    $this->assertText('Created 71 Story nodes.');
+
+    // Remove all nodes.
+    $this->drupalPost('import/node/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 79 nodes.');
+
+    // Import once again.
+    $this->drupalPost('import/node/import', array(), 'Import');
+    $this->assertText('Created 79 Story nodes.');
+
+    // Import a tab separated file.
+    $this->drupalPost('import/node/delete-items', array(), 'Delete');
+    $edit = array(
+      'files[feeds]' => $this->absolutePath() .'/tests/feeds/nodes.tsv',
+      'feeds[FeedsCSVParser][delimiter]' => "TAB",
+    );
+    $this->drupalPost('import/node', $edit, 'Import');
+    $this->assertText('Created 8 Story nodes.');
+  }
+}
+
+/**
+ * Test User import configuration.
+ */
+class FeedsExamplesUserTestCase extends FeedsWebTestCase {
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_import');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer users',
+        )
+      )
+    );
+  }
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Feature: User import'),
+      'description' => t('Test "User import" default configuration.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+    // Import CSV file.
+    $this->importFile('user', $this->absolutePath() .'/tests/feeds/users.csv');
+
+    // Assert result.
+    $this->assertText('Created 4 users.');
+    // 1 user has an invalid email address.
+    $this->assertText('There was 1 user that could not be imported because either their name or their email was empty or not valid. Check import data and mapping settings on User processor.');
+    $this->drupalGet('admin/user/user');
+    $this->assertText('Morticia');
+    $this->assertText('Fester');
+    $this->assertText('Gomez');
+    $this->assertText('Pugsley');
+  }
+}
diff --git a/feeds_news/feeds_news.features.inc b/feeds_news/feeds_news.features.inc
new file mode 100644
index 00000000..810c7621
--- /dev/null
+++ b/feeds_news/feeds_news.features.inc
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Implementation of hook_ctools_plugin_api().
+ */
+function feeds_news_ctools_plugin_api() {
+  list($module, $api) = func_get_args();
+  if ($module == "feeds" && $api == "feeds_importer_default") {
+    return array("version" => 1);
+  }
+}
+
+/**
+ * Implementation of hook_node_info().
+ */
+function feeds_news_node_info() {
+  $items = array(
+    'feed' => array(
+      'name' => t('Feed'),
+      'module' => 'node',
+      'description' => t('Subscribe to RSS or Atom feeds. Creates nodes of the content type "Feed item" from feed content.'),
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'has_body' => '1',
+      'body_label' => t('Body'),
+      'min_word_count' => '0',
+      'help' => '',
+    ),
+    'feed_item' => array(
+      'name' => t('Feed item'),
+      'module' => 'node',
+      'description' => t('This content type is being used for automatically aggregated content from feeds.'),
+      'has_title' => '1',
+      'title_label' => t('Title'),
+      'has_body' => '1',
+      'body_label' => t('Body'),
+      'min_word_count' => '0',
+      'help' => '',
+    ),
+  );
+  return $items;
+}
+
+/**
+ * Implementation of hook_views_api().
+ */
+function feeds_news_views_api() {
+  return array(
+    'api' => '2',
+  );
+}
diff --git a/feeds_news/feeds_news.feeds_importer_default.inc b/feeds_news/feeds_news.feeds_importer_default.inc
new file mode 100644
index 00000000..91642ba4
--- /dev/null
+++ b/feeds_news/feeds_news.feeds_importer_default.inc
@@ -0,0 +1,117 @@
+<?php
+
+/**
+ * Implementation of hook_feeds_importer_default().
+ */
+function feeds_news_feeds_importer_default() {
+  $export = array();
+  $feeds_importer = new stdClass;
+  $feeds_importer->disabled = FALSE; /* Edit this to true to make a default feeds_importer disabled initially */
+  $feeds_importer->api_version = 1;
+  $feeds_importer->id = 'feed';
+  $feeds_importer->config = array(
+    'name' => 'Feed',
+    'description' => 'Import RSS or Atom feeds, create nodes from feed items.',
+    'fetcher' => array(
+      'plugin_key' => 'FeedsHTTPFetcher',
+      'config' => array(
+        'auto_detect_feeds' => FALSE,
+        'use_pubsubhubbub' => FALSE,
+        'designated_hub' => '',
+      ),
+    ),
+    'parser' => array(
+      'plugin_key' => 'FeedsSyndicationParser',
+      'config' => array(),
+    ),
+    'processor' => array(
+      'plugin_key' => 'FeedsNodeProcessor',
+      'config' => array(
+        'content_type' => 'feed_item',
+        'update_existing' => 0,
+        'expire' => '-1',
+        'mappings' => array(
+          '0' => array(
+            'source' => 'title',
+            'target' => 'title',
+            'unique' => FALSE,
+          ),
+          '1' => array(
+            'source' => 'description',
+            'target' => 'body',
+            'unique' => FALSE,
+          ),
+          '2' => array(
+            'source' => 'timestamp',
+            'target' => 'created',
+            'unique' => FALSE,
+          ),
+          '3' => array(
+            'source' => 'url',
+            'target' => 'url',
+            'unique' => TRUE,
+          ),
+          '4' => array(
+            'source' => 'guid',
+            'target' => 'guid',
+            'unique' => TRUE,
+          ),
+        ),
+        'input_format' => 0,
+        'author' => 0,
+      ),
+    ),
+    'content_type' => 'feed',
+    'update' => 0,
+    'import_period' => '1800',
+    'expire_period' => 3600,
+    'import_on_create' => 1,
+  );
+
+  $export['feed'] = $feeds_importer;
+  $feeds_importer = new stdClass;
+  $feeds_importer->disabled = FALSE; /* Edit this to true to make a default feeds_importer disabled initially */
+  $feeds_importer->api_version = 1;
+  $feeds_importer->id = 'opml';
+  $feeds_importer->config = array(
+    'name' => 'OPML import',
+    'description' => 'Import subscriptions from OPML files. Use together with "Feed" configuration.',
+    'fetcher' => array(
+      'plugin_key' => 'FeedsFileFetcher',
+      'config' => array(
+        'direct' => FALSE,
+      ),
+    ),
+    'parser' => array(
+      'plugin_key' => 'FeedsOPMLParser',
+      'config' => array(),
+    ),
+    'processor' => array(
+      'plugin_key' => 'FeedsFeedNodeProcessor',
+      'config' => array(
+        'content_type' => 'feed',
+        'update_existing' => 0,
+        'mappings' => array(
+          '0' => array(
+            'source' => 'title',
+            'target' => 'title',
+            'unique' => FALSE,
+          ),
+          '1' => array(
+            'source' => 'xmlurl',
+            'target' => 'source',
+            'unique' => 1,
+          ),
+        ),
+      ),
+    ),
+    'content_type' => '',
+    'update' => 0,
+    'import_period' => '-1',
+    'expire_period' => 3600,
+    'import_on_create' => 1,
+  );
+
+  $export['opml'] = $feeds_importer;
+  return $export;
+}
diff --git a/feeds_news/feeds_news.info b/feeds_news/feeds_news.info
new file mode 100644
index 00000000..c6f6d7d6
--- /dev/null
+++ b/feeds_news/feeds_news.info
@@ -0,0 +1,14 @@
+core = "6.x"
+dependencies[] = "feeds"
+dependencies[] = "views"
+description = "A news aggregator built with feeds, creates nodes from imported feed items. With OPML import."
+features[ctools][] = "feeds:feeds_importer_default:1"
+features[feeds_importer][] = "feed"
+features[feeds_importer][] = "opml"
+features[node][] = "feed"
+features[node][] = "feed_item"
+features[views][] = "feeds_defaults_feed_items"
+features[views_api][] = "api:2"
+name = "Feeds News"
+package = "Feeds"
+project = "Feeds"
diff --git a/feeds_news/feeds_news.module b/feeds_news/feeds_news.module
new file mode 100644
index 00000000..5c4fce3e
--- /dev/null
+++ b/feeds_news/feeds_news.module
@@ -0,0 +1,3 @@
+<?php
+
+include_once('feeds_news.features.inc');
diff --git a/feeds_news/feeds_news.test b/feeds_news/feeds_news.test
new file mode 100644
index 00000000..d5e9486d
--- /dev/null
+++ b/feeds_news/feeds_news.test
@@ -0,0 +1,149 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Tests for feeds_news feature.
+ */
+
+// Require FeedsWebTestCase class definition.
+require_once(dirname(__FILE__) .'/../tests/feeds.test.inc');
+
+/**
+ * Test Feed configuration.
+ */
+class FeedsExamplesFeedTestCase extends FeedsWebTestCase {
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'features', 'feeds_news');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+  }
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Feature: Feed'),
+      'description' => t('Test "Feed" default configuration. <strong>Requires Features.</strong>'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+    $nid = $this->createFeedNode('feed', NULL, '', 'feed');
+
+    // Assert results.
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'feed_item'"));
+    $this->assertEqual($count, 10, 'Found the correct number of feed item nodes in database.');
+
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 10, 'Found the correct number of records in feeds_node_item.');
+
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Open Atrium Translation Workflow: Two Way Translation Updates'"));
+    $this->assertEqual($count, 1, 'Found title.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Week in DC Tech: October 5th Edition'"));
+    $this->assertEqual($count, 1, 'Found title.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Integrating the Siteminder Access System in an Open Atrium-based Intranet'"));
+    $this->assertEqual($count, 1, 'Found title.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE title = 'Scaling the Open Atrium UI'"));
+    $this->assertEqual($count, 1, 'Found title.');
+
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE url = 'http://developmentseed.org/blog/2009/oct/06/open-atrium-translation-workflow-two-way-updating'"));
+    $this->assertEqual($count, 1, 'Found feed_node_item record.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE url = 'http://developmentseed.org/blog/2009/oct/05/week-dc-tech-october-5th-edition'"));
+    $this->assertEqual($count, 1, 'Found feed_node_item record.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE guid = '974 at http://developmentseed.org'"));
+    $this->assertEqual($count, 1, 'Found feed_node_item record.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item} WHERE guid = '970 at http://developmentseed.org'"));
+    $this->assertEqual($count, 1, 'Found feed_node_item record.');
+
+    // Remove all items
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 10 nodes.');
+
+    // Import again.
+    $this->drupalPost('node/'. $nid .'/import', array(), 'Import');
+    $this->assertText('Created 10 Feed item nodes.');
+
+    // Delete and assert all items gone.
+    $this->drupalPost('node/'. $nid .'/delete-items', array(), 'Delete');
+
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'feed_item'"));
+    $this->assertEqual($count, 0, 'Found the correct number of feed item nodes in database.');
+
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 0, 'Found the correct number of records in feeds_node_item.');
+
+    // Create a batch of nodes.
+    $this->createFeedNodes('feed', 10, 'feed');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {node} WHERE type = 'feed_item'"));
+    $this->assertEqual($count, 100, 'Imported 100 nodes.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_node_item}"));
+    $this->assertEqual($count, 100, 'Found 100 records in feeds_node_item.');
+  }
+}
+
+/**
+ * Test OPML import configuration.
+ */
+class FeedsExamplesOPMLTestCase extends FeedsWebTestCase {
+
+  /**
+   * Set up test.
+   */
+  public function setUp() {
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'feeds_news');
+
+    $this->drupalLogin(
+      $this->drupalCreateUser(
+        array(
+          'administer feeds', 'administer nodes',
+        )
+      )
+    );
+  }
+
+  /**
+   * Describe this test.
+   */
+  public function getInfo() {
+    return array(
+      'name' => t('Feature: OPML import'),
+      'description' => t('Test "OPML import" default configuration.'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Run tests.
+   */
+  public function test() {
+
+    // Import OPML and assert.
+    $file = $this->generateOPML();
+    $this->importFile('opml', $file);
+    $this->assertText('Created 3 feed nodes.');
+    $count = db_result(db_query("SELECT COUNT(*) FROM {feeds_source}"));
+    $this->assertEqual($count, 4, 'Found correct number of items.');
+
+    // Import a feed and then delete all items from it.
+    $this->drupalPost('node/1/import', array(), 'Import');
+    $this->assertText('Created 10 Feed item nodes.');
+    $this->drupalPost('node/1/delete-items', array(), 'Delete');
+    $this->assertText('Deleted 10 nodes.');
+  }
+}
diff --git a/feeds_news/feeds_news.views_default.inc b/feeds_news/feeds_news.views_default.inc
new file mode 100644
index 00000000..f74efb7f
--- /dev/null
+++ b/feeds_news/feeds_news.views_default.inc
@@ -0,0 +1,368 @@
+<?php
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function feeds_news_views_default_views() {
+  $views = array();
+
+  // Exported view: feeds_defaults_feed_items
+  $view = new view;
+  $view->name = 'feeds_defaults_feed_items';
+  $view->description = 'Show feed items for a feed node. Use together with default importer configuration "Feed".';
+  $view->tag = 'Feeds defaults';
+  $view->view_php = '';
+  $view->base_table = 'node';
+  $view->is_cacheable = FALSE;
+  $view->api_version = 2;
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->override_option('relationships', array(
+    'feed_nid' => array(
+      'label' => 'Owner feed',
+      'required' => 1,
+      'id' => 'feed_nid',
+      'table' => 'feeds_node_item',
+      'field' => 'feed_nid',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('fields', array(
+    'url' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'display_as_link' => 1,
+      'exclude' => 1,
+      'id' => 'url',
+      'table' => 'feeds_node_item',
+      'field' => 'url',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+    'title' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 1,
+        'path' => '[url]',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '<h2>',
+        'suffix' => '</h2>',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_node' => 0,
+      'exclude' => 0,
+      'id' => 'title',
+      'table' => 'node',
+      'field' => 'title',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+    'title_1' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'link_to_node' => 1,
+      'exclude' => 1,
+      'id' => 'title_1',
+      'table' => 'node',
+      'field' => 'title',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'feed_nid',
+    ),
+    'nothing' => array(
+      'label' => '',
+      'alter' => array(
+        'text' => 'From [title_1]',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'exclude' => 0,
+      'id' => 'nothing',
+      'table' => 'views',
+      'field' => 'nothing',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+    'body' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'exclude' => 0,
+      'id' => 'body',
+      'table' => 'node_revisions',
+      'field' => 'body',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+    'edit_node' => array(
+      'label' => '',
+      'alter' => array(
+        'alter_text' => 0,
+        'text' => '',
+        'make_link' => 0,
+        'path' => '',
+        'link_class' => '',
+        'alt' => '',
+        'prefix' => '',
+        'suffix' => '',
+        'target' => '',
+        'help' => '',
+        'trim' => 0,
+        'max_length' => '',
+        'word_boundary' => 1,
+        'ellipsis' => 1,
+        'html' => 0,
+        'strip_tags' => 0,
+      ),
+      'empty' => '',
+      'hide_empty' => 0,
+      'empty_zero' => 0,
+      'text' => 'Edit',
+      'exclude' => 0,
+      'id' => 'edit_node',
+      'table' => 'node',
+      'field' => 'edit_node',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('arguments', array(
+    'nid' => array(
+      'default_action' => 'empty',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => 'Articles from %1',
+      'breadcrumb' => '',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'none',
+      'validate_fail' => 'not found',
+      'break_phrase' => 0,
+      'not' => 0,
+      'id' => 'nid',
+      'table' => 'node',
+      'field' => 'nid',
+      'validate_user_argument_type' => 'uid',
+      'validate_user_roles' => array(
+        '2' => 0,
+      ),
+      'relationship' => 'feed_nid',
+      'default_options_div_prefix' => '',
+      'default_argument_fixed' => '',
+      'default_argument_user' => 0,
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'feed' => 0,
+        'feed_item' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(),
+      'validate_argument_type' => 'tid',
+      'validate_argument_transform' => 0,
+      'validate_user_restrict_roles' => 0,
+      'validate_argument_php' => '',
+      'override' => array(
+        'button' => 'Override',
+      ),
+    ),
+  ));
+  $handler->override_option('filters', array(
+    'type' => array(
+      'operator' => 'in',
+      'value' => array(
+        'feed_item' => 'feed_item',
+      ),
+      'group' => '0',
+      'exposed' => FALSE,
+      'expose' => array(
+        'operator' => FALSE,
+        'label' => '',
+      ),
+      'id' => 'type',
+      'table' => 'node',
+      'field' => 'type',
+      'override' => array(
+        'button' => 'Override',
+      ),
+      'relationship' => 'none',
+    ),
+  ));
+  $handler->override_option('access', array(
+    'type' => 'perm',
+    'perm' => 'access content',
+  ));
+  $handler->override_option('cache', array(
+    'type' => 'none',
+  ));
+  $handler->override_option('empty', 'There are no items for this feed at the moment.');
+  $handler->override_option('empty_format', '1');
+  $handler = $view->new_display('page', 'Page', 'page_1');
+  $handler->override_option('arguments', array(
+    'nid' => array(
+      'default_action' => 'empty',
+      'style_plugin' => 'default_summary',
+      'style_options' => array(),
+      'wildcard' => 'all',
+      'wildcard_substitution' => 'All',
+      'title' => 'All items from %1',
+      'breadcrumb' => '',
+      'default_argument_type' => 'fixed',
+      'default_argument' => '',
+      'validate_type' => 'node',
+      'validate_fail' => 'not found',
+      'break_phrase' => 0,
+      'not' => 0,
+      'id' => 'nid',
+      'table' => 'node',
+      'field' => 'nid',
+      'validate_user_argument_type' => 'uid',
+      'validate_user_roles' => array(
+        '2' => 0,
+      ),
+      'relationship' => 'feed_nid',
+      'default_options_div_prefix' => '',
+      'default_argument_fixed' => '',
+      'default_argument_user' => 0,
+      'default_argument_php' => '',
+      'validate_argument_node_type' => array(
+        'feed' => 'feed',
+        'feed_item' => 0,
+        'story' => 0,
+      ),
+      'validate_argument_node_access' => 0,
+      'validate_argument_nid_type' => 'nid',
+      'validate_argument_vocabulary' => array(),
+      'validate_argument_type' => 'tid',
+      'validate_argument_transform' => 0,
+      'validate_user_restrict_roles' => 0,
+      'validate_argument_php' => '',
+      'override' => array(
+        'button' => 'Use default',
+      ),
+    ),
+  ));
+  $handler->override_option('path', 'node/%/feed-items');
+  $handler->override_option('menu', array(
+    'type' => 'tab',
+    'title' => 'View items',
+    'description' => '',
+    'weight' => '0',
+    'name' => 'navigation',
+  ));
+  $handler->override_option('tab_options', array(
+    'type' => 'none',
+    'title' => '',
+    'description' => '',
+    'weight' => 0,
+    'name' => 'navigation',
+  ));
+
+  $views[$view->name] = $view;
+
+  return $views;
+}
-- 
GitLab