From 079da32990ca3e5d828bbe94efd13dc43d32a9c0 Mon Sep 17 00:00:00 2001
From: Alex Barth <alex_b@53995.no-reply.drupal.org>
Date: Fri, 15 Jan 2010 19:44:54 +0000
Subject: [PATCH] #623448: David Goode, alex_b, et al.: Date mapper.

---
 CHANGELOG.txt                           |   1 +
 libraries/common_syndication_parser.inc |   3 +
 mappers/date.inc                        |  64 ++++
 plugins/FeedsParser.inc                 | 374 +++++++++++++++++++++---
 tests/feeds/googlenewstz.rss2           |   8 +
 tests/feeds_mapper_date.test            | 109 +++++++
 6 files changed, 526 insertions(+), 33 deletions(-)
 create mode 100644 mappers/date.inc
 create mode 100644 tests/feeds/googlenewstz.rss2
 create mode 100644 tests/feeds_mapper_date.test

diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 37d88faa..343d27ea 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -3,6 +3,7 @@
 Feeds 6.x 1.0 XXXXXXX, 20XX-XX-XX
 ---------------------------------
 
+- #623448: David Goode, alex_b, et al.: Date mapper.
 - #624088: mongolito404, David Goode, alex_b: Imagefield/filefield mapper,
   formalize feed elements.
 - #584034: aaroncouch, mongolito404: Views integration.
diff --git a/libraries/common_syndication_parser.inc b/libraries/common_syndication_parser.inc
index 2e5a7467..680d0589 100644
--- a/libraries/common_syndication_parser.inc
+++ b/libraries/common_syndication_parser.inc
@@ -439,6 +439,9 @@ function _parser_common_syndication_RSS20_parse($feed_XML) {
  *  The timestamp of the string or the current time if can't be parsed
  */
 function _parser_common_syndication_parse_date($date_str) {
+  // PHP < 5.3 doesn't like the GMT- notation for parsing timezones.
+  $date_str = str_replace("GMT-", "-", $date_str);
+  $date_str = str_replace("GMT+", "+", $date_str);
   $parsed_date = strtotime($date_str);
   if ($parsed_date === FALSE || $parsed_date == -1) {
     $parsed_date = _parser_common_syndication_parse_w3cdtf($date_str);
diff --git a/mappers/date.inc b/mappers/date.inc
new file mode 100644
index 00000000..9926a7c2
--- /dev/null
+++ b/mappers/date.inc
@@ -0,0 +1,64 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * On behalf implementation of Feeds mapping API for date
+ */
+
+/**
+ * Implementation of hook_feeds_node_processor_targets_alter().
+ *
+ * @see FeedsNodeProcessor::getMappingTargets().
+ *
+ * @todo Only provides "end date" target if field allows it.
+ */
+function date_feeds_node_processor_targets_alter(&$targets, $content_type) {
+  $info = content_types($content_type);
+  if (isset($info['fields']) && count($info['fields'])) {
+    foreach ($info['fields'] as $field_name => $field) {
+      if (in_array($field['type'], array('date', 'datestamp', 'datetime'))) {
+        $name = isset($field['widget']['label']) ? $field['widget']['label'] : $field_name;
+        $targets[$field_name .':start'] = array(
+          'name' => $name .': Start',
+          'callback' => 'date_feeds_set_target',
+          'description' => t('The start date for the !name field. Also use if mapping both start and end.', array('!name' => $name)),
+        );
+        $targets[$field_name .':end'] = array(
+          'name' => $name .': End',
+          'callback' => 'date_feeds_set_target',
+          'description' => t('The end date for the @name field.', array('@name' => $name)),
+        );
+      }
+    }
+  }
+}
+
+/**
+ * Implementation of hook_feeds_set_target().
+ *
+ * @param $node
+ *   The target node.
+ * @param $field_name
+ *   The name of field on the target node to map to.
+ * @param $feed_element
+ *   The value to be mapped. Should be either a (flexible) date string
+ *   or a FeedsDateTimeElement object.
+ *
+ * @todo Support array of values for dates.
+ */
+function date_feeds_set_target($node, $target, $feed_element) {
+  list($field_name, $sub_field) = split(':', $target);
+  if (!($feed_element instanceof FeedsDateTimeElement)) {
+    if (is_array($feed_element)) {
+      $feed_element = $feed_element[0];
+    }
+    if ($sub_field == 'end') {
+      $feed_element = new FeedsDateTimeElement(NULL, $feed_element);
+    }
+    else {
+      $feed_element = new FeedsDateTimeElement($feed_element, NULL);
+    }
+  }
+  $feed_element->buildDateField($node, $field_name);
+}
\ No newline at end of file
diff --git a/plugins/FeedsParser.inc b/plugins/FeedsParser.inc
index 117d14ed..3068c4ed 100644
--- a/plugins/FeedsParser.inc
+++ b/plugins/FeedsParser.inc
@@ -1,6 +1,61 @@
 <?php
 // $Id$
 
+/**
+ * Abstract class, defines interface for parsers.
+ */
+abstract class FeedsParser extends FeedsPlugin {
+
+  /**
+   * Parse content fetched by fetcher.
+   *
+   * Extending classes must implement this method.
+   *
+   * @param $batch
+   *   FeedsImportBatch returned by fetcher.
+   * @param FeedsSource $source
+   *   Source information.
+   */
+  public abstract function parse(FeedsImportBatch $batch, FeedsSource $source);
+
+  /**
+   * Clear all caches for results for given source.
+   *
+   * @param FeedsSource $source
+   *   Source information for this expiry. Implementers can choose to only clear
+   *   caches pertaining to this source.
+   */
+  public function clear(FeedsSource $source) {}
+
+  /**
+   * Declare the possible mapping sources that this parser produces.
+   *
+   * @return
+   *   An array of mapping sources, or FALSE if the sources can be defined by
+   *   typing a value in a text field.
+   *
+   *   Example:
+   *   array(
+   *     'title' => t('Title'),
+   *     'created' => t('Published date'),
+   *     'url' => t('Feed item URL'),
+   *     'guid' => t('Feed item GUID'),
+   *   )
+   */
+  public function getMappingSources() {
+    return FALSE;
+  }
+
+  /**
+   * Get an element identified by $element_key of the given item.
+   * The element key corresponds to the values in the array returned by
+   * FeedsParser::getMappingSources().
+   */
+  public function getSourceElement($item, $element_key) {
+    return isset($item[$element_key]) ? $item[$element_key] : '';
+  }
+}
+
 /**
  * Defines an element of a parsed result. Such an element can be a simple type,
  * a complex type (derived from FeedsElement) or an array of either.
@@ -43,56 +98,309 @@ class FeedsElement {
 }
 
 /**
- * Abstract class, defines interface for parsers.
+ * Defines a date element of a parsed result (including ranges, repeat).
  */
-abstract class FeedsParser extends FeedsPlugin {
+class FeedsDateTimeElement extends FeedsElement {
+
+  // Start date and end date.
+  public $start;
+  public $end;
 
   /**
-   * Parse content fetched by fetcher.
+   * Constructor.
    *
-   * Extending classes must implement this method.
+   * @param $start
+   *   A FeedsDateTime object or a date as accepted by FeedsDateTime.
+   * @param $end
+   *   A FeedsDateTime object or a date as accepted by FeedsDateTime.
+   * @param $tz
+   *   A PHP DateTimeZone object.
+   */
+  public function __construct($start = NULL, $end = NULL, $tz = NULL) {
+    $this->start = (!isset($start) || ($start instanceof FeedsDateTime)) ? $start : new FeedsDateTime($start, $tz);
+    $this->end = (!isset($end) || ($end instanceof FeedsDateTime)) ? $end : new FeedsDateTime($end, $tz);
+  }
+
+  /**
+   * Override FeedsElement::getValue().
+   */
+  public function getValue() {
+    return $this->start;
+  }
+
+  /**
+   * Implementation of toString magic php method.
+   */
+  public function __toString() {
+    $val = $this->getValue();
+    if ($val) {
+      return $val->format('U');
+    }
+    return '';
+  }
+
+  /**
+   * Merge this field with another. Most stuff goes down when merging the two
+   * sub-dates.
    *
-   * @param $batch
-   *   FeedsImportBatch returned by fetcher.
-   * @param FeedsSource $source
-   *   Source information.
+   * @see FeedsDateTime
    */
-  public abstract function parse(FeedsImportBatch $batch, FeedsSource $source);
+  public function merge(FeedsDateTimeElement $other) {
+    $this2 = clone $this;
+    if ($this->start && $other->start) {
+      $this2->start = $this->start->merge($other->start);
+    }
+    elseif ($other->start) {
+      $this2->start = clone $other->start;
+    }
+    elseif ($this->start) {
+      $this2->start = clone $this->start;
+    }
+
+    if ($this->end && $other->end) {
+      $this2->end = $this->end->merge($other->end);
+    }
+    elseif ($other->end) {
+      $this2->end = clone $other->end;
+    }
+    elseif ($this->end) {
+      $this2->end = clone $this->end;
+    }
+    return $this2;
+  }
 
   /**
-   * Clear all caches for results for given source.
+   * Helper method for buildDateField(). Build a FeedsDateTimeElement object
+   * from a standard formatted node.
+   */
+  protected static function readDateField($node, $field_name) {
+    $field = content_fields($field_name);
+    $ret = new FeedsDateTimeElement();
+    if ($node->{$field_name}[0]['date'] instanceof FeedsDateTime) {
+      $ret->start = $node->{$field_name}[0]['date'];
+    }
+    if ($node->{$field_name}[0]['date2'] instanceof FeedsDateTime) {
+      $ret->end = $node->{$field_name}[0]['date2'];
+    }
+    return $ret;
+  }
+
+  /**
+   * Build a node's date CCK field from our object.
    *
-   * @param FeedsSource $source
-   *   Source information for this expiry. Implementers can choose to only clear
-   *   caches pertaining to this source.
+   * @param $node
+   *   The node to build the date field on.
+   * @param $field_name
+   *   The name of the field to build.
    */
-  public function clear(FeedsSource $source) {}
+  public function buildDateField($node, $field_name) {
+    $field = content_fields($field_name);
+    $oldfield = FeedsDateTimeElement::readDateField($node, $field_name);
+    // Merge with any preexisting objects on the field; we take precedence.
+    $oldfield = $this->merge($oldfield);
+    $use_start = $oldfield->start;
+    $use_end = $oldfield->end;
+
+    // Set timezone if not already in the FeedsDateTime object
+    $to_tz = date_get_timezone($field['tz_handling'], date_default_timezone_name());
+    $temp = new FeedsDateTime($to_tz, NULL);
+
+    $db_tz = '';
+    if ($use_start) {
+      $use_start = $use_start->merge($temp);
+      if (!date_timezone_is_valid($use_start->getTimezone()->getName())) {
+        $use_start->setTimezone(new DateTimeZone("UTC"));
+      }
+      $db_tz = date_get_timezone_db($field['tz_handling'], $use_start->getTimezone()->getName());
+    }
+    if ($use_end) {
+      $use_end = $use_end->merge($temp);
+      if (!date_timezone_is_valid($use_end->getTimezone()->getName())) {
+        $use_end->setTimezone(new DateTimeZone("UTC"));
+      }
+      if (!$db_tz) {
+        $db_tz = date_get_timezone_db($field['tz_handling'], $use_end->getTimezone()->getName());
+      }
+    }
+    if (!$db_tz) {
+      return;
+    }
+
+    $db_tz = new DateTimeZone($db_tz);
+    if (!isset($node->{$field_name})) {
+      $node->{$field_name} = array();
+    }
+    if ($use_start) {
+      $node->{$field_name}[0]['timezone'] = $use_start->getTimezone()->getName();
+      $node->{$field_name}[0]['offset'] = $use_start->getOffset();
+      $use_start->setTimezone($db_tz);
+      $node->{$field_name}[0]['date'] = $use_start;
+      /**
+       * @todo the date_type_format line could be simplified based upon a patch
+       *   DO issue #259308 could affect this, follow up on at some point.
+       *   Without this, all granularity info is lost.
+       *   $use_start->format(date_type_format($field['type'], $use_start->granularity));
+       */
+      $node->{$field_name}[0]['value'] = $use_start->format(date_type_format($field['type']));
+    }
+    if ($use_end) {
+      // Don't ever use end to set timezone (for now)
+      $node->{$field_name}[0]['offset2'] = $use_end->getOffset();
+      $use_end->setTimezone($db_tz);
+      $node->{$field_name}[0]['date2'] = $use_end;
+      $node->{$field_name}[0]['value2'] = $use_end->format(date_type_format($field['type']));
+    }
+  }
+}
+
+/**
+ * Extend PHP DateTime class with granularity handling, merge functionality and
+ * slightly more flexible initialization parameters.
+ *
+ * This class is a Drupal independent extension of the >= PHP 5.2 DateTime
+ * class.
+ *
+ * @see FeedsDateTimeElement class
+ */
+class FeedsDateTime extends DateTime {
+  public $granularity = array();
+  protected static $allgranularity = array('year', 'month', 'day', 'hour', 'minute', 'second', 'zone');
 
   /**
-   * Declare the possible mapping sources that this parser produces.
+   * Overridden constructor.
    *
-   * @return
-   *   An array of mapping sources, or FALSE if the sources can be defined by
-   *   typing a value in a text field.
+   * @param $time
+   *   time string, flexible format including timestamp.
+   * @param $tz
+   *   PHP DateTimeZone object, NULL allowed
+   */
+  public function __construct($time = '', $tz = NULL) {
+    if (is_numeric($time)) {
+      // Assume timestamp.
+      $time = "@". $time;
+    }
+    // PHP < 5.3 doesn't like the GMT- notation for parsing timezones.
+    $time = str_replace("GMT-", "-", $time);
+    $time = str_replace("GMT+", "+", $time);
+    parent::__construct($time, $tz ? $tz : new DateTimeZone("UTC"));
+    $this->setGranularityFromTime($time, $tz);
+    if (!preg_match('/[a-zA-Z]/', $this->getTimezone()->getName())) {
+      // This tz was given as just an offset, which causes problems
+      $this->setTimezone(new DateTimeZone("UTC"));
+    }
+  }
+
+  /**
+   * This function will keep this object's values by default.
+   */
+  public function merge(FeedsDateTime $other) {
+    $other_tz = $other->getTimezone();
+    $this_tz = $this->getTimezone();
+    // Figure out which timezone to use for combination.
+    $use_tz = ($this->hasGranularity('zone') || !$other->hasGranularity('zone')) ? $this_tz : $other_tz;
+
+    $this2 = clone $this;
+    $this2->setTimezone($use_tz);
+    $other->setTimezone($use_tz);
+    $val = $this2->toArray();
+    $otherval = $other->toArray();
+    foreach (self::$allgranularity as $g) {
+      if ($other->hasGranularity($g) && !$this2->hasGranularity($g)) {
+        // The other class has a property we don't; steal it.
+        $this2->addGranularity($g);
+        $val[$g] = $otherval[$g];
+      }
+    }
+    $other->setTimezone($other_tz);
+
+    $this2->setDate($val['year'], $val['month'], $val['day']);
+    $this2->setTime($val['hour'], $val['minute'], $val['second']);
+    return $this2;
+  }
+
+  /**
+   * Overrides default DateTime function. Only changes output values if
+   * actually had time granularity. This should be used as a "converter" for
+   * output, to switch tzs.
    *
-   *   Example:
-   *   array(
-   *     'title' => t('Title'),
-   *     'created' => t('Published date'),
-   *     'url' => t('Feed item URL'),
-   *     'guid' => t('Feed item GUID'),
-   *   )
+   * In order to set a timezone for a datetime that doesn't have such
+   * granularity, merge() it with one that does.
    */
-  public function getMappingSources() {
-    return FALSE;
+  public function setTimezone(DateTimeZone $tz, $force = FALSE) {
+    // PHP 5.2.6 has a fatal error when setting a date's timezone to itself.
+    // http://bugs.php.net/bug.php?id=45038
+    if (version_compare(PHP_VERSION, '5.2.7', '<') && $tz == $this->getTimezone()) {
+      $tz = new DateTimeZone($tz->getName());
+    }
+
+    if (!$this->hasTime() || !$this->hasGranularity('zone') || $force) {
+      // this has no time or timezone granularity, so timezone doesn't mean much
+      // We set the timezone using the method, which will change the day/hour, but then we switch back
+      $arr = $this->toArray();
+      parent::setTimezone($tz);
+      $this->setDate($arr['year'], $arr['month'], $arr['day']);
+      $this->setTime($arr['hour'], $arr['minute'], $arr['second']);
+      return;
+    }
+    parent::setTimezone($tz);
   }
 
   /**
-   * Get an element identified by $element_key of the given item.
-   * The element key corresponds to the values in the array returned by
-   * FeedsParser::getMappingSources().
+   * Safely adds a granularity entry to the array.
    */
-  public function getSourceElement($item, $element_key) {
-    return isset($item[$element_key]) ? $item[$element_key] : '';
+  public function addGranularity($g) {
+    $this->granularity[] = $g;
+    $this->granularity = array_unique($this->granularity);
   }
-}
\ No newline at end of file
+
+  /**
+   * Removes a granularity entry from the array.
+   */
+  public function removeGranularity($g) {
+    if ($key = array_search($g, $this->granularity)) {
+      unset($this->granularity[$key]);
+    }
+  }
+
+  /**
+   * Checks granularity array for a given entry.
+   */
+  public function hasGranularity($g) {
+    return in_array($g, $this->granularity);
+  }
+
+  /**
+   * Returns whether this object has time set. Used primarily for timezone
+   * conversion and fomratting.
+   *
+   * @todo currently very simplistic, but effective, see usage
+   */
+  public function hasTime() {
+    return $this->hasGranularity('hour');
+  }
+
+  /**
+   * Protected function to find the granularity given by the arguments to the
+   * constructor.
+   */
+  protected function setGranularityFromTime($time, $tz) {
+    $this->granularity = array();
+    $temp = date_parse($time);
+    // This PHP method currently doesn't have resolution down to seconds, so if there is some time, all will be set.
+    foreach (self::$allgranularity AS $g) {
+      if (is_numeric($temp[$g]) || ($g == 'zone' && $temp['zone_type'] > 0)) {
+        $this->granularity[] = $g;
+      }
+    }
+    if ($tz) {
+      $this->addGranularity('zone');
+    }
+  }
+
+  /**
+   * Helper to return all standard date parts in an array.
+   */
+  protected function toArray() {
+    return array('year' => $this->format('Y'), 'month' => $this->format('m'), 'day' => $this->format('d'), 'hour' => $this->format('H'), 'minute' => $this->format('i'), 'second' => $this->format('s'), 'zone' => $this->format('e'));
+  }
+}
diff --git a/tests/feeds/googlenewstz.rss2 b/tests/feeds/googlenewstz.rss2
new file mode 100644
index 00000000..66276d3d
--- /dev/null
+++ b/tests/feeds/googlenewstz.rss2
@@ -0,0 +1,8 @@
+<rss version="2.0"><channel><generator>NFE/1.0</generator><title>Top Stories - Google News</title><link>http://news.google.com?pz=1&amp;ned=us&amp;hl=en</link><language>en</language><webMaster>news-feedback@google.com</webMaster><copyright>&amp;copy;2010 Google</copyright><pubDate>Wed, 06 Jan 2010 15:00:01 GMT+00:00</pubDate><lastBuildDate>Wed, 06 Jan 2010 15:00:01 GMT+00:00</lastBuildDate><image><title>Top Stories - Google News</title><url>http://www.gstatic.com/news/img/bluelogo/en_us/news.gif</url><link>http://news.google.com?pz=1&amp;ned=us&amp;hl=en</link></image>
+<item><title>First thoughts: Dems&apos; Black Tuesday - msnbc.com</title><link>http://news.google.com/news/url?fd=R&amp;sa=T&amp;url=http%3A%2F%2Ffirstread.msnbc.msn.com%2Farchive%2F2010%2F01%2F06%2F2166474.aspx&amp;usg=AFQjCNFdbsCs9ORClyOyAOcv9NTwcsKzZQ</link><guid isPermaLink="false">tag:news.google.com,2005:cluster=17593687403189</guid><category>Top Stories</category><pubDate>Wed, 06 Jan 2010 14:26:27 GMT-05:00</pubDate><description>&lt;table border=&quot;0&quot; cellpadding=&quot;2&quot; cellspacing=&quot;7&quot; style=&quot;vertical-align:top;&quot;&gt;&lt;tr&gt;&lt;td width=&quot;80&quot; align=&quot;center&quot; valign=&quot;top&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.guardian.co.uk%2Fcommentisfree%2Fmichaeltomasky%2F2010%2Fjan%2F06%2Fchris-dodd-byron-dorgan&amp;amp;usg=AFQjCNGqpLv5bhzKoO6HCYhiJ54B1AQiMw&quot;&gt;&lt;img src=&quot;http://nt0.ggpht.com/news/tbn/XPqi_u5kO1YrtM/6.jpg&quot; alt=&quot;&quot; border=&quot;1&quot; width=&quot;80&quot; height=&quot;80&quot; /&gt;&lt;br /&gt;&lt;font size=&quot;-2&quot;&gt;The Guardian&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; class=&quot;j&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-top:0.8em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;lh&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Ffirstread.msnbc.msn.com%2Farchive%2F2010%2F01%2F06%2F2166474.aspx&amp;amp;usg=AFQjCNFdbsCs9ORClyOyAOcv9NTwcsKzZQ&quot;&gt;&lt;b&gt;First thoughts: Dems&amp;#39; Black Tuesday&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;b&gt;&lt;font color=&quot;#6f6f6f&quot;&gt;msnbc.com&lt;/font&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;Democrats experience a Black Tuesday with retirements from Dodd, Dorgan, and Ritter… While Dodd&amp;#39;s exit is probably a political blessing, the same can&amp;#39;t be said for Dorgan&amp;#39;s or Ritter&amp;#39;s decisions… Republicans are one step closer to putting 11 Senate &lt;b&gt;...&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FpoliticsNews%2FidUSTRE6052ET20100106&amp;amp;usg=AFQjCNHBEpKDZvHhYMOcNY2De4EDLwhXxQ&quot;&gt;Dodd&amp;#39;s decision underscores Democrats&amp;#39; vulnerability&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Reuters&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.chron.com%2Fdisp%2Fstory.mpl%2Fap%2Ftop%2Fall%2F6801127.html&amp;amp;usg=AFQjCNFmZ6GwjUTYcIyZ7jP6IE17m0t8bw&quot;&gt;Dodd, D-Conn., retiring from Senate; AG to run&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Houston Chronicle&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.miamiherald.com%2Fnews%2Fpolitics%2FAP%2Fstory%2F1411697.html&amp;amp;usg=AFQjCNEtPzHHaLMIX4EMc68ieP7SHfHCfA&quot;&gt;Sen. Dodd won&amp;#39;t seek re-election&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;MiamiHerald.com&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot; class=&quot;p&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.nytimes.com%2Faponline%2F2010%2F01%2F06%2Fus%2FAP-CT-DoddRetirement-Bl.html&amp;amp;usg=AFQjCNHQssq-uyg6reJLjTsMtKjJj_83aQ&quot;&gt;&lt;nobr&gt;New York Times&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.washingtonpost.com%2Fwp-dyn%2Fcontent%2Farticle%2F2010%2F01%2F06%2FAR2010010601258.html&amp;amp;usg=AFQjCNGO_LBmoYqmETiD2Y2gdjU9IVxEww&quot;&gt;&lt;nobr&gt;Washington Post&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.guardian.co.uk%2Fworld%2F2010%2Fjan%2F06%2Fdemocrat-senators-governors-election-obama&amp;amp;usg=AFQjCNGU16BT2JSIHSYDl831UMHGtchvsQ&quot;&gt;&lt;nobr&gt;The Guardian&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;br /&gt;&lt;font class=&quot;p&quot; size=&quot;-1&quot;&gt;&lt;a class=&quot;p&quot; href=&quot;http://news.google.com/news/more?pz=1&amp;amp;ned=us&amp;amp;ncl=dBeDIZhDLhfRYOM2C0cJa6WmMPy3M&amp;amp;topic=h&quot;&gt;&lt;nobr&gt;&lt;b&gt;all 1,751 news articles&amp;nbsp;&amp;raquo;&lt;/b&gt;&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;/div&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description></item>
+<item><title>Obama wants to fast track a final health care bill - USA Today</title><link>http://news.google.com/news/url?fd=R&amp;sa=T&amp;url=http%3A%2F%2Fcontent.usatoday.com%2Fcommunities%2Ftheoval%2Fpost%2F2010%2F01%2Fobama-wants-to-fast-track-a-final-health-care-bill%2F1&amp;usg=AFQjCNF1sXxYAFz26OQqKIWh3rBJZxgksg</link><guid isPermaLink="false">tag:news.google.com,2005:cluster=17593688083752</guid><category>Top Stories</category><pubDate>Wed, 06 Jan 2010 13:21:20 GMT+03:00</pubDate><description>&lt;table border=&quot;0&quot; cellpadding=&quot;2&quot; cellspacing=&quot;7&quot; style=&quot;vertical-align:top;&quot;&gt;&lt;tr&gt;&lt;td width=&quot;80&quot; align=&quot;center&quot; valign=&quot;top&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FidUSTRE5B83ZG20100105&amp;amp;usg=AFQjCNEVrKzaUBu2zEjPQPQ4hzCy6D09LA&quot;&gt;&lt;img src=&quot;http://nt1.ggpht.com/news/tbn/FWkTTQtlAJkNWM/6.jpg&quot; alt=&quot;&quot; border=&quot;1&quot; width=&quot;80&quot; height=&quot;80&quot; /&gt;&lt;br /&gt;&lt;font size=&quot;-2&quot;&gt;Reuters&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; class=&quot;j&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-top:0.8em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;lh&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fcontent.usatoday.com%2Fcommunities%2Ftheoval%2Fpost%2F2010%2F01%2Fobama-wants-to-fast-track-a-final-health-care-bill%2F1&amp;amp;usg=AFQjCNF1sXxYAFz26OQqKIWh3rBJZxgksg&quot;&gt;&lt;b&gt;Obama wants to fast track a final health care bill&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;b&gt;&lt;font color=&quot;#6f6f6f&quot;&gt;USA Today&lt;/font&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;The White House didn&amp;#39;t say much about last night&amp;#39;s health care talks between President Obama and congressional Democrats, but officials made it clear they&amp;#39;re cool with fast-tracking the final phase of legislation, with no public hearings and no &lt;b&gt;...&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.medpagetoday.com%2FWashington-Watch%2FReform%2F17812&amp;amp;usg=AFQjCNGFLIoORNDfDJFNXxiNWxuAdyMDNQ&quot;&gt;Congress Likely to Combine Healthcare Bills Informally&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;MedPage Today&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwashingtontimes.com%2Fnews%2F2010%2Fjan%2F06%2Freforms-bode-ill-for-tax-free-health-accounts%2F%3Ffeat%3Dhome_headlines&amp;amp;usg=AFQjCNG9QTVx8kHcEaFWdxr3sKIItoB2Dw&quot;&gt;Reforms bode ill for tax-free health accounts&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Washington Times&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fedition.cnn.com%2F2010%2FPOLITICS%2F01%2F06%2Fobama.dems.health.care%2F&amp;amp;usg=AFQjCNHELvYyQ3TAaXqhQtOR5dNkg9qLIA&quot;&gt;Sources: Obama, Dems to hold informal talks on health care&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;CNN International&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot; class=&quot;p&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.nytimes.com%2F2010%2F01%2F06%2Fus%2Fpolitics%2F06cong.html&amp;amp;usg=AFQjCNGcq7OwgK4J1pGeWDZmKrMH9W-Jxg&quot;&gt;&lt;nobr&gt;New York Times&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.boston.com%2Fnews%2Fnation%2Fwashington%2Farticles%2F2010%2F01%2F06%2Fdemocrats_focus_on_health_consensus%2F&amp;amp;usg=AFQjCNElF4ajwViPqbvpPD9R2OYeONCE1A&quot;&gt;&lt;nobr&gt;Boston Globe&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.kaiserhealthnews.org%2FDaily-Reports%2F2010%2FJanuary%2F06%2FEyes-on-Pelosi-Health-Care.aspx&amp;amp;usg=AFQjCNFS_LBgfNddk8KD2n091RFrqyu15w&quot;&gt;&lt;nobr&gt;Kaiser Health News&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;br /&gt;&lt;font class=&quot;p&quot; size=&quot;-1&quot;&gt;&lt;a class=&quot;p&quot; href=&quot;http://news.google.com/news/more?pz=1&amp;amp;ned=us&amp;amp;ncl=dZLcGGGFNPbQ-1My5ui0FO5ST5zTM&amp;amp;topic=h&quot;&gt;&lt;nobr&gt;&lt;b&gt;all 1,917 news articles&amp;nbsp;&amp;raquo;&lt;/b&gt;&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;/div&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description></item>
+<item><title>Why the Nexus One Makes Other Android Phones Obsolete - PC World</title><link>http://news.google.com/news/url?fd=R&amp;sa=T&amp;url=http%3A%2F%2Fwww.pcworld.com%2Farticle%2F186006%2Fwhy_the_nexus_one_makes_other_android_phones_obsolete.html&amp;usg=AFQjCNF4WnQcKVu-P5jICC0SNtPAH2IPVw</link><guid isPermaLink="false">tag:news.google.com,2005:cluster=17593685844960</guid><category>Top Stories</category><pubDate>Wed, 06 Jan 2010 13:42:47 GMT+00:00</pubDate><description>&lt;table border=&quot;0&quot; cellpadding=&quot;2&quot; cellspacing=&quot;7&quot; style=&quot;vertical-align:top;&quot;&gt;&lt;tr&gt;&lt;td width=&quot;80&quot; align=&quot;center&quot; valign=&quot;top&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.cbc.ca%2Ftechnology%2Fstory%2F2010%2F01%2F05%2Fgoogle-phone.html&amp;amp;usg=AFQjCNGheVBsiY2XOoZ1MhvhbR_Lh6zGPA&quot;&gt;&lt;img src=&quot;http://nt3.ggpht.com/news/tbn/u_YKGJKq82TQoM/6.jpg&quot; alt=&quot;&quot; border=&quot;1&quot; width=&quot;80&quot; height=&quot;80&quot; /&gt;&lt;br /&gt;&lt;font size=&quot;-2&quot;&gt;CBC.ca&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; class=&quot;j&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-top:0.8em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;lh&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.pcworld.com%2Farticle%2F186006%2Fwhy_the_nexus_one_makes_other_android_phones_obsolete.html&amp;amp;usg=AFQjCNF4WnQcKVu-P5jICC0SNtPAH2IPVw&quot;&gt;&lt;b&gt;Why the Nexus One Makes Other Android Phones Obsolete&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;b&gt;&lt;font color=&quot;#6f6f6f&quot;&gt;PC World&lt;/font&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;Google&amp;#39;s new &amp;quot;superphone&amp;quot; runs the latest and greatest version of Android, but don&amp;#39;t expect to see it on older Android phones anytime soon. The Google Nexus One, unveiled on Tuesday, has all the bells and whistles to challenge Apple&amp;#39;s ever-popular &lt;b&gt;...&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.crn.com%2Fmobile%2F222200427&amp;amp;usg=AFQjCNEVYevIt9wqQZ8y4wspFqATjYQ_lA&quot;&gt;What Google&amp;#39;s Nexus One Really Means&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;ChannelWeb&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Ffeeds.wired.com%2F~r%2Fwired%2Findex%2F~3%2FMO-ku8369hw%2F&amp;amp;usg=AFQjCNFgvwgM3LIoGoTrMSNiqAvYPsZZAQ&quot;&gt;Google Debuts Android-Powered Nexus One &amp;#39;Superphone&amp;#39;&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Wired News&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FidUS418924234220100106&amp;amp;usg=AFQjCNHQ-U2aRSw0DP891RC59gRmkZIPjQ&quot;&gt;Google Phone Makes a Small Splash&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Reuters&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot; class=&quot;p&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.mobileburn.com%2Fnews.jsp%3FId%3D8489&amp;amp;usg=AFQjCNG5LCR6KvvWgtSFFGxctJ4VwoqGpQ&quot;&gt;&lt;nobr&gt;Mobile Burn&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.theinquirer.net%2Finquirer%2Fnews%2F1567644%2Fgoogle-releases-nexus-smartphone&amp;amp;usg=AFQjCNFTgpWj8iAnYZIsnC06jkJzkYbQEA&quot;&gt;&lt;nobr&gt;Inquirer&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.computerworld.com%2Fs%2Farticle%2F9143115%2FNexus_One_another_tactic_in_Google_s_ad_revenue_strategy&amp;amp;usg=AFQjCNEEev8nSakJJ9vfVc6DuW6jtkM4RQ&quot;&gt;&lt;nobr&gt;Computerworld&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;br /&gt;&lt;font class=&quot;p&quot; size=&quot;-1&quot;&gt;&lt;a class=&quot;p&quot; href=&quot;http://news.google.com/news/more?pz=1&amp;amp;ned=us&amp;amp;ncl=djgUAiDaCDB60kMkkiB30PWRy8X7M&amp;amp;topic=h&quot;&gt;&lt;nobr&gt;&lt;b&gt;all 3,450 news articles&amp;nbsp;&amp;raquo;&lt;/b&gt;&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;/div&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description></item>
+<item><title>NEWSMAKER-New Japan finance minister a fiery battler - Reuters</title><link>http://news.google.com/news/url?fd=R&amp;sa=T&amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FidUSTOE60509W20100106&amp;usg=AFQjCNGc_qEms8qqrYAmUdQTbFgBlsa51A</link><guid isPermaLink="false">tag:news.google.com,2005:cluster=17593685670703</guid><category>Top Stories</category><pubDate>Wed, 06 Jan 2010 14:05:40 GMT+08:00</pubDate><description>&lt;table border=&quot;0&quot; cellpadding=&quot;2&quot; cellspacing=&quot;7&quot; style=&quot;vertical-align:top;&quot;&gt;&lt;tr&gt;&lt;td width=&quot;80&quot; align=&quot;center&quot; valign=&quot;top&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.rte.ie%2Fbusiness%2F2010%2F0106%2Fjapan.html&amp;amp;usg=AFQjCNGQWWOq_Q67WM9NLpuu12eNgAMhbA&quot;&gt;&lt;img src=&quot;http://nt1.ggpht.com/news/tbn/BVlP-eNLpkIPKM/6.jpg&quot; alt=&quot;&quot; border=&quot;1&quot; width=&quot;80&quot; height=&quot;80&quot; /&gt;&lt;br /&gt;&lt;font size=&quot;-2&quot;&gt;RTE.ie&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; class=&quot;j&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-top:0.8em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;lh&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FidUSTOE60509W20100106&amp;amp;usg=AFQjCNGc_qEms8qqrYAmUdQTbFgBlsa51A&quot;&gt;&lt;b&gt;NEWSMAKER-New Japan finance minister a fiery battler&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;b&gt;&lt;font color=&quot;#6f6f6f&quot;&gt;Reuters&lt;/font&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;TOKYO, Jan 6 (Reuters) - Japan&amp;#39;s new finance minister, Naoto Kan, is a fiery ruling party heavyweight who faces the tough task of trying to stimulate the economy without upsetting investors by bloating an already huge public debt. &lt;b&gt;...&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fonline.wsj.com%2Farticle%2FBT-CO-20100106-706288.html%3Fmod%3DWSJ_World_MIDDLEHeadlinesAsia&amp;amp;usg=AFQjCNG0SB2DSq-JypF3hTmbn6g8sD_gfw&quot;&gt;Kan To Take Over As Japan&amp;#39;s Finance Chief&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Wall Street Journal&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fedition.cnn.com%2F2010%2FWORLD%2Fasiapcf%2F01%2F06%2Fjapan.finance.minister.fujii%2F&amp;amp;usg=AFQjCNG30pVGVZd1rJDOBbKu58fIDOe7Hg&quot;&gt;Japanese finance minister Fujii quits&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;CNN International&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fhome.kyodo.co.jp%2Fmodules%2FfstStory%2Findex.php%3Fstoryid%3D479144&amp;amp;usg=AFQjCNGCKkHTxC2EiSqVwMXQOxpfwsEtEw&quot;&gt;FOCUS: Figure of Ozawa looms again behind Fujii&amp;#39;s resignation&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Kyodo News&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot; class=&quot;p&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.businessweek.com%2Fnews%2F2010-01-06%2Fyen-drops-versus-dollar-as-recovery-fujii-concern-curbs-demand.html&amp;amp;usg=AFQjCNGDSOaJ1bpQh7PsMmjY991lvKkGWg&quot;&gt;&lt;nobr&gt;BusinessWeek&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.marketwatch.com%2Fstory%2Fdeputy-pm-kan-named-as-japans-finance-minister-2010-01-06&amp;amp;usg=AFQjCNEBsJZmpuzhn-K7v44k_IOatX2Nig&quot;&gt;&lt;nobr&gt;MarketWatch&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.nytimes.com%2F2010%2F01%2F06%2Fworld%2Fasia%2F06japan.html&amp;amp;usg=AFQjCNFs6L5M8MCCG7VuPDcTmE9ek121hw&quot;&gt;&lt;nobr&gt;New York Times&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;br /&gt;&lt;font class=&quot;p&quot; size=&quot;-1&quot;&gt;&lt;a class=&quot;p&quot; href=&quot;http://news.google.com/news/more?pz=1&amp;amp;ned=us&amp;amp;ncl=dNT65aGS3zkAmIM8rSpYdo38DRxVM&amp;amp;topic=h&quot;&gt;&lt;nobr&gt;&lt;b&gt;all 1,156 news articles&amp;nbsp;&amp;raquo;&lt;/b&gt;&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;/div&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description></item>
+<item><title>Yemen Detains Al-Qaeda Suspects After Embassy Threats - Bloomberg</title><link>http://news.google.com/news/url?fd=R&amp;sa=T&amp;url=http%3A%2F%2Fwww.bloomberg.com%2Fapps%2Fnews%3Fpid%3D20601102%26sid%3DalTEErVe0CIs&amp;usg=AFQjCNGKnUWVDulzUwkJgxAU6QNOPFiHeg</link><guid isPermaLink="false">tag:news.google.com,2005:cluster=17593688042489</guid><category>Top Stories</category><pubDate>Wed, 06 Jan 2010 14:26:39 GMT+03:00</pubDate><description>&lt;table border=&quot;0&quot; cellpadding=&quot;2&quot; cellspacing=&quot;7&quot; style=&quot;vertical-align:top;&quot;&gt;&lt;tr&gt;&lt;td width=&quot;80&quot; align=&quot;center&quot; valign=&quot;top&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.telegraph.co.uk%2Fnews%2Fworldnews%2Fmiddleeast%2Fyemen%2F6937316%2FYemen-orders-troops-into-al-Qaeda-strongholds.html&amp;amp;usg=AFQjCNExyEywr12YTiceNZtzlq1NKX-EgQ&quot;&gt;&lt;img src=&quot;http://nt3.ggpht.com/news/tbn/awRvMhtywz3c-M/6.jpg&quot; alt=&quot;&quot; border=&quot;1&quot; width=&quot;80&quot; height=&quot;80&quot; /&gt;&lt;br /&gt;&lt;font size=&quot;-2&quot;&gt;Telegraph.co.uk&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; class=&quot;j&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-top:0.8em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;lh&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.bloomberg.com%2Fapps%2Fnews%3Fpid%3D20601102%26sid%3DalTEErVe0CIs&amp;amp;usg=AFQjCNGKnUWVDulzUwkJgxAU6QNOPFiHeg&quot;&gt;&lt;b&gt;Yemen Detains Al-Qaeda Suspects After Embassy Threats&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;b&gt;&lt;font color=&quot;#6f6f6f&quot;&gt;Bloomberg&lt;/font&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;Jan. 6 (Bloomberg) -- Yemeni security forces said they arrested three suspected al-Qaeda militants linked to a cell of the terrorist group blamed for threats against the US Embassy and other foreign missions. &lt;b&gt;...&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww1.voanews.com%2Fenglish%2Fnews%2Fmiddle-east%2FYemen-Claims-3-Al-Qaida-Militants-Captured-in-Connection-with-Embassy-Threat-80780967.html&amp;amp;usg=AFQjCNH5X3tiJ8vsrZoEHFWnJDmw6k3sFw&quot;&gt;Yemen Claims 3 Al-Qaida Militants Captured in Connection with Embassy Threat&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Voice of America&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fnews.bbc.co.uk%2F1%2Fhi%2Fworld%2Fmiddle_east%2F8443078.stm&amp;amp;usg=AFQjCNGYwV-rqv5PegAz5SsldiRvr1dr_g&quot;&gt;Yemen &amp;#39;arrests al-Qaeda suspects&amp;#39; wounded in raid&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;BBC News&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fedition.cnn.com%2F2010%2FWORLD%2Fmeast%2F01%2F06%2Fyemen.al.qaeda%2F&amp;amp;usg=AFQjCNFSfbY9qkFcgLRyGQLjfNex-5KNQw&quot;&gt;Yemen arrests 3 al Qaeda suspects&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;CNN International&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot; class=&quot;p&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.google.com%2Fhostednews%2Fafp%2Farticle%2FALeqM5h4NbgbHk88RSPSpOCG5Cg6f6FrvA&amp;amp;usg=AFQjCNHN_z8Ds-OxNhIRl_MZxRtEeAp_dg&quot;&gt;&lt;nobr&gt;AFP&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.chicagotribune.com%2Fnews%2Fchi-tc-nw-yemen-qaeda-0105-0106jan06%2C0%2C3246858.story&amp;amp;usg=AFQjCNHto_VTKl2AdlO7yF7D9Uk3CkMlxw&quot;&gt;&lt;nobr&gt;Chicago Tribune&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.ynetnews.com%2Farticles%2F0%2C7340%2CL-3830342%2C00.html&amp;amp;usg=AFQjCNHK0DJcyGgEyjaz-fxTXgicYFGnLQ&quot;&gt;&lt;nobr&gt;Ynetnews&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;br /&gt;&lt;font class=&quot;p&quot; size=&quot;-1&quot;&gt;&lt;a class=&quot;p&quot; href=&quot;http://news.google.com/news/more?pz=1&amp;amp;ned=us&amp;amp;ncl=duEsXKdHWTVEzZMnfUiaVj_DuDpAM&amp;amp;topic=h&quot;&gt;&lt;nobr&gt;&lt;b&gt;all 1,584 news articles&amp;nbsp;&amp;raquo;&lt;/b&gt;&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;/div&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description></item>
+<item><title>Egypt, Hamas exchange fire on Gaza frontier, 1 dead - Reuters</title><link>http://news.google.com/news/url?fd=R&amp;sa=T&amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FidUSTRE60526A20100106&amp;usg=AFQjCNG4UuyUmz-Wd6YhmbdvupkbHbHYAA</link><guid isPermaLink="false">tag:news.google.com,2005:cluster=17593688298004</guid><category>Top Stories</category><pubDate>Wed, 06 Jan 2010 14:26:26 GMT-10:00</pubDate><description>&lt;table border=&quot;0&quot; cellpadding=&quot;2&quot; cellspacing=&quot;7&quot; style=&quot;vertical-align:top;&quot;&gt;&lt;tr&gt;&lt;td width=&quot;80&quot; align=&quot;center&quot; valign=&quot;top&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fenglish.aljazeera.net%2Fnews%2Fmiddleeast%2F2010%2F01%2F201016123715308843.html&amp;amp;usg=AFQjCNF5jDZ_Ucs9aLP_5ohKQfuUwTh3Dg&quot;&gt;&lt;img src=&quot;http://nt3.ggpht.com/news/tbn/L9ZIsOJouvA_fM/6.jpg&quot; alt=&quot;&quot; border=&quot;1&quot; width=&quot;80&quot; height=&quot;80&quot; /&gt;&lt;br /&gt;&lt;font size=&quot;-2&quot;&gt;Aljazeera.net&lt;/font&gt;&lt;/a&gt;&lt;/font&gt;&lt;/td&gt;&lt;td valign=&quot;top&quot; class=&quot;j&quot;&gt;&lt;font style=&quot;font-size:85%;font-family:arial,sans-serif&quot;&gt;&lt;br /&gt;&lt;div style=&quot;padding-top:0.8em;&quot;&gt;&lt;img alt=&quot;&quot; height=&quot;1&quot; width=&quot;1&quot; /&gt;&lt;/div&gt;&lt;div class=&quot;lh&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.reuters.com%2Farticle%2FidUSTRE60526A20100106&amp;amp;usg=AFQjCNG4UuyUmz-Wd6YhmbdvupkbHbHYAA&quot;&gt;&lt;b&gt;Egypt, Hamas exchange fire on Gaza frontier, 1 dead&lt;/b&gt;&lt;/a&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;b&gt;&lt;font color=&quot;#6f6f6f&quot;&gt;Reuters&lt;/font&gt;&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;GAZA (Reuters) - An Egyptian soldier was killed and four Palestinians were wounded in a gunbattle on Wednesday during a protest against an anti-smuggling wall Cairo is building on the Gaza border. The violence was the most serious between Egyptian and &lt;b&gt;...&lt;/b&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fenglish.aljazeera.net%2Fnews%2Fmiddleeast%2F2010%2F01%2F201016123715308843.html&amp;amp;usg=AFQjCNF5jDZ_Ucs9aLP_5ohKQfuUwTh3Dg&quot;&gt;Lethal clashes at Gaza-Egypt border&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Aljazeera.net&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.google.com%2Fhostednews%2Fafp%2Farticle%2FALeqM5hlyBEcozp_DcZhUdakcB2mnTmUoQ&amp;amp;usg=AFQjCNHFBHDUXezq_jQgJFOxw_6c7eghtg&quot;&gt;Gaza gunfire kills Egypt policeman: Egypt state TV&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;AFP&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fnews.xinhuanet.com%2Fenglish%2F2010-01%2F06%2Fcontent_12766842.htm&amp;amp;usg=AFQjCNGsyoHSwxXprG-AyOwX12dmdd9Q5g&quot;&gt;Calm back to Egypt&amp;#39;s borders with Gaza after clashes&lt;/a&gt;&lt;font size=&quot;-1&quot; color=&quot;#6f6f6f&quot;&gt;&lt;nobr&gt;Xinhua&lt;/nobr&gt;&lt;/font&gt;&lt;/font&gt;&lt;br /&gt;&lt;font size=&quot;-1&quot; class=&quot;p&quot;&gt;&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.ynetnews.com%2Farticles%2F0%2C7340%2CL-3830579%2C00.html&amp;amp;usg=AFQjCNGsfWllg2QfhV4pX-MXEl8VRuIqsg&quot;&gt;&lt;nobr&gt;Ynetnews&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.nytimes.com%2Faponline%2F2010%2F01%2F05%2Fworld%2FAP-ML-Palestinians-Sealing-Gaza.html&amp;amp;usg=AFQjCNEf0LP7EnK0t3uIOBOtsPm9rDuVug&quot;&gt;&lt;nobr&gt;New York Times&lt;/nobr&gt;&lt;/a&gt;&amp;nbsp;-&lt;a href=&quot;http://news.google.com/news/url?fd=R&amp;amp;sa=T&amp;amp;url=http%3A%2F%2Fwww.guardian.co.uk%2Fworld%2F2010%2Fjan%2F06%2Fgeorge-galloway-gaza-aid-convoy&amp;amp;usg=AFQjCNFQyAgvHovIr6y9DmwmjghS7WNRXQ&quot;&gt;&lt;nobr&gt;The Guardian&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;br /&gt;&lt;font class=&quot;p&quot; size=&quot;-1&quot;&gt;&lt;a class=&quot;p&quot; href=&quot;http://news.google.com/news/more?pz=1&amp;amp;ned=us&amp;amp;ncl=djNuENxfWRzRYjMzw1nruQqIJxslM&amp;amp;topic=h&quot;&gt;&lt;nobr&gt;&lt;b&gt;all 635 news articles&amp;nbsp;&amp;raquo;&lt;/b&gt;&lt;/nobr&gt;&lt;/a&gt;&lt;/font&gt;&lt;/div&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description></item>
+<description>Google News</description></channel></rss>
\ No newline at end of file
diff --git a/tests/feeds_mapper_date.test b/tests/feeds_mapper_date.test
new file mode 100644
index 00000000..105eb936
--- /dev/null
+++ b/tests/feeds_mapper_date.test
@@ -0,0 +1,109 @@
+<?php
+// $Id$
+
+/**
+ * @file
+ * Test case for CCK date field mapper mappers/content.inc.
+ */
+
+require_once(drupal_get_path('module', 'feeds') . '/tests/feeds_mapper_test.inc');
+
+/**
+ * Class for testing Feeds <em>content</em> mapper.
+ *
+ * @todo: Add test method iCal
+ * @todo: Add test method for end date
+ */
+class FeedsMapperDateTestCase extends FeedsMapperTestCase {
+
+	public static function getInfo() {
+    return array(
+      'name' => t('Mapper: Date'),
+      'description' => t('Test Feeds Mapper support for CCK Date fields'),
+      'group' => t('Feeds'),
+    );
+  }
+
+  /**
+   * Set up the test.
+   */
+  public function setUp() {
+    // Call parent setup with the required module.
+    parent::setUp('feeds', 'feeds_ui', 'ctools', 'content', 'date_api', 'date');
+
+    // Create user and login.
+    $this->drupalLogin($this->drupalCreateUser(
+        array(
+          'administer content types',
+          'administer feeds',
+          'administer nodes',
+          'administer site configuration',
+        )
+    ));
+  }
+
+  /**
+   * Basic test loading a single entry CSV file.
+   */
+  public function test() {
+    // Create content type.
+  	$typename = $this->createContentType(NULL, array(
+      'date' => 'date',
+      'datestamp' => 'datestamp',
+      'datetime' => 'datetime',
+    ));
+
+    // Create and configure importer.
+    $this->createFeedConfiguration('Date RSS', 'daterss');
+    $this->setSettings('daterss', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER,));
+    $this->setPlugin('daterss', 'FeedsFileFetcher');
+    $this->setPlugin('daterss', 'FeedsSyndicationParser');
+    $this->setSettings('daterss', 'FeedsNodeProcessor', array('content_type' => $typename));
+    $this->addMappings('daterss', array(
+      array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      array(
+        'source' => 'description',
+        'target' => 'body',
+      ),
+      array(
+        'source' => 'timestamp',
+        'target' => 'field_date:start',
+      ),
+      array(
+        'source' => 'timestamp',
+        'target' => 'field_datestamp:start',
+      ),
+    ));
+
+    // Import CSV file.
+    $this->importFile('daterss', $this->absolutePath() .'/tests/feeds/googlenewstz.rss2');
+    $this->assertText('Created 6 '. $typename .' nodes.');
+
+    // Check the imported nodes.
+    $values = array(
+      '01/06/2010 - 19:26',
+      '01/06/2010 - 10:21',
+      '01/06/2010 - 13:42',
+      '01/06/2010 - 06:05',
+      '01/06/2010 - 11:26',
+      '01/07/2010 - 00:26',
+      );
+    for ($i = 1; $i <= 6; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertCCKFieldValue('date', $values[$i-1]);
+      $this->assertCCKFieldValue('datestamp', $values[$i-1]);
+    }
+  }
+
+  protected function getFormFieldsNames($field_name, $index) {
+    if (in_array($field_name, array('date', 'datetime', 'datestamp'))) {
+      return array("field_{$field_name}[{$index}][value][date]");
+    }
+    else {
+      return parent::getFormFieldsNames($field_name, $index);
+    }
+  }
+}
-- 
GitLab