diff --git a/wp-content/plugins/feedwordpress/admin-ui.php b/wp-content/plugins/feedwordpress/admin-ui.php
index d9ba9c3a62c98bee9c465a6cb5e4d290008a5e40..d9eee616d283643e4ec5e95f9f7e0c611ae01f50 100644
--- a/wp-content/plugins/feedwordpress/admin-ui.php
+++ b/wp-content/plugins/feedwordpress/admin-ui.php
@@ -746,38 +746,68 @@ function fwp_option_box_closer () {
 }
 
 function fwp_tags_box ($tags, $object, $params = array()) {
+	$params = wp_parse_args($params, array( // Default values
+	'taxonomy' => 'post_tag',
+	'textarea_name' => NULL,
+	'textarea_id' => NULL,
+	'input_id' => NULL,
+	'input_name' => NULL,
+	'id' => NULL,
+	'box_title' => __('Post Tags'),
+	));
+	
 	if (!is_array($tags)) : $tags = array(); endif;
-	$tax_name = (isset($params['taxonomy']) ? $params['taxonomy'] : 'post_tag');
+	
+	$tax_name = $params['taxonomy'];
+	$taxonomy = get_taxonomy($params['taxonomy']);
+	$disabled = (!current_user_can($taxonomy->cap->assign_terms) ? 'disabled="disabled"' : '');
+	
 	$desc = "<p style=\"font-size:smaller;font-style:bold;margin:0\">Tag $object as...</p>";
 
-	if (isset($params['textarea_name'])) :
-		$textAreaName = $params['textarea_name'];
-	else :
-		$textAreaName = "tax_input[$tax_name]";
+	if (is_null($params['textarea_name'])) :
+		$params['textarea_name'] = "tax_input[$tax_name]";
+	endif;
+	if (is_null($params['textarea_id'])) :
+		$params['textarea_id'] = "tax-input-${tax_name}";
 	endif;
+	if (is_null($params['input_id'])) :
+		$params['input_id'] = "new-tag-${tax_name}";
+	endif;
+	if (is_null($params['input_name'])) :
+		$params['input_name'] = "newtag[$tax_name]";
+	endif;
+	
+	if (is_null($params['id'])) :
+		$params['id'] = $tax_name;
+	endif;
+	
 	print $desc;
 	$helps = __('Separate tags with commas.');
 	$box['title'] = __('Tags');
 	?>
-		<div class="tagsdiv" id="<?php echo $tax_name; ?>">
-	        <div class="jaxtag">
-	        <div class="nojs-tags hide-if-js">
-	        <p><?php _e('Add or remove tags'); ?></p>
-	        <textarea name="<?php echo esc_html($textAreaName); ?>" class="the-tags" id="tax-input[<?php echo $tax_name; ?>]"><?php echo esc_attr(implode(",", $tags)); ?></textarea></div>
+<div class="tagsdiv" id="<?php echo $params['id']; ?>">
+	<div class="jaxtag">
+	<div class="nojs-tags hide-if-js">
+    <p><?php echo $taxonomy->labels->add_or_remove_items; ?></p>
+	<textarea name="<?php echo $params['textarea_name']; ?>" class="the-tags" id="<?php echo $params['textarea_id']; ?>"><?php echo esc_attr(implode(",", $tags)); ?></textarea></div>
 	
-	        <div class="ajaxtag hide-if-no-js">
-	                <label class="screen-reader-text" for="new-tag-<?php echo $tax_name; ?>"><?php echo $box['title']; ?></label>
-	                <div class="taghint"><?php _e('Add new tag'); ?></div>
-	                <p>
-	                <input type="text" id="new-tag-<?php echo $tax_name; ?>" name="newtag[<?php echo $tax_name; ?>]" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
-	                <input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" tabindex="3" />
-	                </p>
-	        </div></div>
-	        <p class="howto"><?php echo $helps; ?></p>
-	        <div class="tagchecklist"></div>
-	        </div>
-	        <p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php printf( __('Choose from the most used tags in %s'), $box['title'] ); ?></a></p>
-        <?php
+	<?php if ( current_user_can($taxonomy->cap->assign_terms) ) :?>
+	<div class="ajaxtag hide-if-no-js">
+		<label class="screen-reader-text" for="<?php echo $params['input_id']; ?>"><?php echo $params['box_title']; ?></label>
+		<div class="taghint"><?php echo $taxonomy->labels->add_new_item; ?></div>
+		<p><input type="text" id="<?php print $params['input_id']; ?>" name="<?php print $params['input_name']; ?>" class="newtag form-input-tip" size="16" autocomplete="off" value="" />
+		<input type="button" class="button tagadd" value="<?php esc_attr_e('Add'); ?>" tabindex="3" /></p>
+	</div>
+	<p class="howto"><?php echo esc_attr( $taxonomy->labels->separate_items_with_commas ); ?></p>
+	<?php endif; ?>
+	</div>
+	
+	<div class="tagchecklist"></div>
+</div>
+<?php if ( current_user_can($taxonomy->cap->assign_terms) ) : ?>
+<p class="hide-if-no-js"><a href="#titlediv" class="tagcloud-link" id="link-<?php echo $tax_name; ?>"><?php echo $taxonomy->labels->choose_from_most_used; ?></a></p>
+<?php endif;
+
 }
 
 function fwp_category_box ($checked, $object, $tags = array(), $params = array()) {
@@ -946,6 +976,12 @@ class FeedWordPressSettingsUI {
 			background-position:0 top;
 			background-repeat:repeat-x;
 		}
+		
+		.update-results {
+			max-width: 100%;
+			overflow: auto;
+		}
+
 		</style>
 		<?php
 	} /* FeedWordPressSettingsUI::admin_styles () */
@@ -1076,7 +1112,7 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible =
 				// Prep: Get last updated timestamp
 				$sLink = new SyndicatedLink($link->link_id);
 				if (!is_null($sLink->setting('update/last'))) :
-					$lastUpdated = fwp_time_elapsed($sLink->setting('update/last'));
+					$lastUpdated = 'Last checked '. fwp_time_elapsed($sLink->setting('update/last'));
 				else :
 					$lastUpdated = __('None yet');
 				endif;
@@ -1101,19 +1137,41 @@ function fwp_syndication_manage_page_links_table_rows ($links, $page, $visible =
 						."</div>\n";
 				endif;
 
-				$nextUpdate = "<div style='font-style:italic;size:0.9em'>Ready for next update ";
-				if (isset($sLink->settings['update/ttl']) and is_numeric($sLink->settings['update/ttl'])) :
-					if (isset($sLink->settings['update/timed']) and $sLink->settings['update/timed']=='automatically') :
-						$next = $sLink->settings['update/last'] + ((int) $sLink->settings['update/ttl'] * 60);
+				$nextUpdate = "<div style='max-width: 30.0em; font-size: 0.9em;'><div style='font-style:italic;'>";
+				
+				$ttl = $sLink->setting('update/ttl');
+				if (is_numeric($ttl)) :
+					$next = $sLink->setting('update/last') + $sLink->setting('update/fudge') + ((int) $ttl * 60);
+					if ('automatically'==$sLink->setting('update/timed')) :
+						if ($next < time()) :
+							$nextUpdate .= 'Ready and waiting to be updated since ';
+						else :
+							$nextUpdate .= 'Scheduled for next update ';
+						endif;
 						$nextUpdate .= fwp_time_elapsed($next);
 						if (FEEDWORDPRESS_DEBUG) : $nextUpdate .= " [".(($next-time())/60)." minutes]"; endif;
 					else :
-						$nextUpdate .= "every ".$sLink->settings['update/ttl']." minute".(($sLink->settings['update/ttl']!=1)?"s":"");
+						$lastUpdated .= " &middot; Next ";
+						if ($next < time()) :
+							$lastUpdated .= 'ASAP';
+						elseif ($next - time() < 60) :
+							$lastUpdated .= fwp_time_elapsed($next);
+						elseif ($next - time() < 60*60*24) :
+							$lastUpdated .= gmdate('g:ia', $next + (get_option('gmt_offset') * 3600));
+						else :
+							$lastUpdated .= gmdate('F j', $next + (get_option('gmt_offset') * 3600));
+						endif;
+						
+						$nextUpdate .= "Scheduled to be checked for updates every ".$ttl." minute".(($ttl!=1)?"s":"")."</div><div style='size:0.9em; margin-top: 0.5em'>	This update schedule was requested by the feed provider";
+						if ($sLink->setting('update/xml')) :
+							$nextUpdate .= " using a standard <code style=\"font-size: inherit; padding: 0; background: transparent\">&lt;".$sLink->setting('update/xml')."&gt;</code> element";
+						endif;
+						$nextUpdate .= ".";
 					endif;
 				else:
-					$nextUpdate .= "as soon as possible";
+					$nextUpdate .= "Scheduled for update as soon as possible";
 				endif;
-				$nextUpdate .= "</div>";
+				$nextUpdate .= "</div></div>";
 
 				unset($sLink);
 				
diff --git a/wp-content/plugins/feedwordpress/authors-page.php b/wp-content/plugins/feedwordpress/authors-page.php
index 8a36068207b9dcdfbba5d445471424a10641ac8a..d2438e88592c19c605b00b6066be39f3ccd30010 100644
--- a/wp-content/plugins/feedwordpress/authors-page.php
+++ b/wp-content/plugins/feedwordpress/authors-page.php
@@ -24,6 +24,9 @@ class FeedWordPressAuthorsPage extends FeedWordPressAdminPage {
 	
 	function refresh_author_list () {
 		$this->authorlist = fwp_author_list();
+
+		// Case-insensitive "natural" alphanumeric sort. Preserves key/value associations.
+		if (function_exists('natcasesort')) : natcasesort($this->authorlist); endif;
 	}
 	
 	/*static*/ function syndicated_authors_box ($page, $box = NULL) {
@@ -45,6 +48,26 @@ class FeedWordPressAuthorsPage extends FeedWordPressAdminPage {
 		?>
 <table class="form-table">
 <?php
+if ($page->for_default_settings()) :
+?>
+<tr><th>Unmatched authors</th>
+<td><span>Authors who haven&#8217;t been syndicated before</span>
+  <select style="max-width: 27.0em" id="unfamiliar-author" name="unfamiliar_author" onchange="contextual_appearance('unfamiliar-author', 'unfamiliar-author-newuser', 'unfamiliar-author-default', 'newuser', 'inline');">
+    <option value="create"<?php print $unfamiliar['create']; ?>>will have a new author account created for them</option>
+    <?php foreach ($page->authorlist as $author_id => $author_name) : ?>
+      <option value="<?php echo $author_id; ?>"<?php print (isset($unfamiliar[$author_id]) ? $unfamiliar[$author_id] : ''); ?>>will have their posts attributed to <?php echo $author_name; ?></option>
+    <?php endforeach; ?>
+    <option value="newuser">will have their posts attributed to a new user...</option>
+    <option value="filter"<?php print $unfamiliar['filter'] ?>>get filtered out</option>
+  </select>
+
+  <span id="unfamiliar-author-newuser">named <input type="text" name="unfamiliar_author_newuser" value="" /></span></p>
+  </td>
+</tr>
+
+<?php
+endif;
+
 if ($page->for_feed_settings()) :
 	$map = $this->link->setting('map authors', NULL, array());
 ?>
@@ -55,8 +78,10 @@ authors?</p>
 <li><p><input type="radio" name="author_rules_name[all]" value="*"
 <?php if (isset($map['name']['*'])) : $author_action = $map['name']['*']; ?>
 	checked="checked"
-<?php else : $author_action = NULL; ?>
-<?php endif; ?>
+<?php
+	else :
+		$author_action = NULL;
+	endif; ?>
 	/> All posts syndicated
 from this feed <select class="author-rules" id="author-rules-all"
 name="author_rules_action[all]" onchange="contextual_appearance('author-rules-all', 'author-rules-all-newuser', 'author-rules-all-default', 'newuser', 'inline');">
diff --git a/wp-content/plugins/feedwordpress/diagnostics-page.php b/wp-content/plugins/feedwordpress/diagnostics-page.php
index ad9fe528316c632e3a6e6409fd604e0464d09f3b..d062b00f3290822cf9eedf988c20ef246ddc1574 100644
--- a/wp-content/plugins/feedwordpress/diagnostics-page.php
+++ b/wp-content/plugins/feedwordpress/diagnostics-page.php
@@ -70,6 +70,7 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
 		if (isset($post['submit'])
 		or isset($post['save'])) :
 			update_option('feedwordpress_debug', $post['feedwordpress_debug']);
+			update_option('feedwordpress_secret_key', $post['feedwordpress_secret_key']);
 			
 			if (!isset($post['diagnostics_output'])
 			or !is_array($post['diagnostics_output'])) :
@@ -106,8 +107,9 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
 	} /* FeedWordPressDiagnosticsPage::accept_POST () */
 
 	function info_box ($page, $box = NULL) {
-			$link_category_id = FeedWordPress::link_category_id();
-		?>
+		global $feedwordpress;
+		$link_category_id = FeedWordPress::link_category_id();
+	?>
 		<table class="edit-form narrow">
 		<thead style="display: none">
 		<th scope="col">Topic</th>
@@ -146,6 +148,14 @@ class FeedWordPressDiagnosticsPage extends FeedWordPressAdminPage {
 		</table>
 		<?php endif; ?></td>
 		</tr>
+		
+		<tr>
+		<th scope="row"><?php _e('Secret Key:'); ?></th>
+		<td><input type="text" name="feedwordpress_secret_key" value="<?php print esc_attr($feedwordpress->secret_key()); ?>" />
+		<p class="setting-description">This is used to control access to some diagnostic testing functions. You can change it to any string you want,
+		but only tell it to people you trust to help you troubleshoot your
+		FeedWordPress installation. Keep it secret&#8212;keep it safe.</p></td>
+		</tr>
 		</table>
 
 		<?php
@@ -228,7 +238,8 @@ testing but absolutely inappropriate for a production server.</p>
 		$hours = get_option('feedwordpress_diagnostics_persistent_errors_hours', 2);
 		$fields = apply_filters('feedwordpress_diagnostics', array(
 			'Update Diagnostics' => array(
-				'updated_feeds' => 'as each feed checked for updates',
+				'update_schedule:check' => 'whenever a FeedWordPress checks in on the update schedule', 
+				'updated_feeds' => 'as each feed is checked for updates',
 				'updated_feeds:errors:persistent' => 'when attempts to update a feed have resulted in errors</label> <label>for at least <input type="number" min="1" max="360" step="1" name="diagnostics_persistent_error_hours" value="'.$hours.'" /> hours',
 				'updated_feeds:errors' => 'any time FeedWordPress encounters any errors while checking a feed for updates',
 				'syndicated_posts' => 'as each syndicated post is added to the database',
@@ -236,8 +247,14 @@ testing but absolutely inappropriate for a production server.</p>
 				'memory_usage' => 'indicating how much memory was used',
 			),
 			'Syndicated Post Details' => array(
+				'feed_items:freshness' => 'as FeedWordPress decides whether to treat an item as a new post, an update, or a duplicate of an existing post',
+				'feed_items:rejected' => 'when FeedWordPress rejects a post without syndicating it',
 				'syndicated_posts:meta_data' => 'as syndication meta-data is added on the post',
 			),
+			'Advanced Diagnostics' => array(
+				'feed_items:freshness:sql' => 'when FeedWordPress issues the SQL query it uses to decide whether to treat items as new, updates, or duplicates', 
+				'syndicated_posts:static_meta_data' => 'providing meta-data about syndicated posts in the Edit Posts interface',
+			),
 		), $page);
 		
 		foreach ($fields as $section => $items) :
diff --git a/wp-content/plugins/feedwordpress/feeds-page.php b/wp-content/plugins/feedwordpress/feeds-page.php
index c96537c504acc68f180fe3ed991571cd5ff8e2bd..3aa1c3bb73f22caf302e6f3c86f8dc368035cb42 100644
--- a/wp-content/plugins/feedwordpress/feeds-page.php
+++ b/wp-content/plugins/feedwordpress/feeds-page.php
@@ -175,7 +175,8 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
 	} /* FeedWordPressFeedsPage::updated_posts_box() */
 
 	/*static*/ function global_feeds_box ($page, $box = NULL) {
-		$automatic_updates = get_option('feedwordpress_automatic_updates');
+		global $feedwordpress;
+		$automatic_updates = $feedwordpress->automatic_update_hook(array('setting only' => true));
 		$update_time_limit = (int) get_option('feedwordpress_update_time_limit');
 
 		// Hey, ho, let's go...
@@ -263,6 +264,30 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
 			?></td>
 		</tr>
 
+		<tr>
+		<th scope="row"><?php print __('Minimum Interval:'); ?></th>
+		<td><p style="margin-top:0px">Some feeds include standard elements that
+		request a specific update schedule. If the interval requested by the
+		feed provider is <em>longer</em> than FeedWordPress's normal scheduling,
+		FeedWordPress will always respect their request to slow down. But what
+		should it do if the update interval is <em>shorter</em> than the schedule set above?</p>
+		<?php
+			$this->setting_radio_control(
+				'update/minimum', 'update_minimum',
+				/*options=*/ array(
+					'no' => 'Speed up and accept the interval from the feed provider',
+					'yes' => 'Keep pace and use the longer scheduling from FeedWordPress',
+				),
+				/*params=*/ array(
+					'setting-default' => NULL,
+					'global-setting-default' => 'no',
+					'default-input-value' => 'default',
+				)
+			);
+		?>
+		</td>
+		</tr>
+		
 		<?php if ($this->for_default_settings()) : ?>
 		
 		<tr>
@@ -905,7 +930,7 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
 			update_option('feedwordpress_cat_id', $post['syndication_category']);
 			
 			if (!isset($post['automatic_updates']) or !in_array($post['automatic_updates'], array('init', 'shutdown'))) :
-				$automatic_updates = false;
+				$automatic_updates = NULL;
 			else :
 				$automatic_updates = $post['automatic_updates'];
 			endif;
@@ -939,6 +964,10 @@ class FeedWordPressFeedsPage extends FeedWordPressAdminPage {
 			endif;
 			$this->update_setting('fetch timeout', $timeout);
 		endif;
+
+		if (isset($post['update_minimum'])) :
+			$this->update_setting('update/minimum', $post['update_minimum']);
+		endif;
 		
 		$this->updatedPosts->accept_POST($post);
 		parent::save_settings($post);
diff --git a/wp-content/plugins/feedwordpress/feedtime.class.php b/wp-content/plugins/feedwordpress/feedtime.class.php
index 7aab3388fa8d6f9a9243b24fdd98b636119c1c46..5cfc3a26a081a69fcde0a68d279242f697cfe64b 100644
--- a/wp-content/plugins/feedwordpress/feedtime.class.php
+++ b/wp-content/plugins/feedwordpress/feedtime.class.php
@@ -11,7 +11,7 @@ class FeedTime {
 		$this->set($time);
 	} /* FeedTime constructor */
 	
-	function set ($time) {
+	function set ($time, $recurse = false) {
 		$this->rep = $time;
 		$this->ts = NULL;
 		if (is_numeric($time)) : // Presumably a Unix-epoch timestamp
@@ -23,7 +23,7 @@ class FeedTime {
 			if ($this->failed()) :
 				// In some versions of PHP, strtotime() does not support
 				// the UT timezone. Since UT is by definition within 1
-				// second of UTC, we'll just convert it here to avoid
+				// second of UTC, we'll just convert it preemptively to avoid
 				// problems.
 				$time = preg_replace(
 					'/(\s)UT$/',
@@ -31,6 +31,12 @@ class FeedTime {
 					$time
 				);
 				$this->ts = strtotime($time);
+				
+				if ($this->failed()
+				and preg_match('/^(.*)([+\-][0-9]+|\s+[A-Za-z]{1,3})$/', $time, $matches)) :
+					// Try dropping the time zone and recurse
+					$this->set($matches[1], /*recurse=*/ true);
+				endif;
 			endif;
 		endif;
 	} /* FeedTime::set() */
diff --git a/wp-content/plugins/feedwordpress/feedwordpress-elements.js b/wp-content/plugins/feedwordpress/feedwordpress-elements.js
index 838ba66cfc41b73215e13773d681e02e1099e062..50333aba83eddb218dab711926ee1b46cb8ede26 100644
--- a/wp-content/plugins/feedwordpress/feedwordpress-elements.js
+++ b/wp-content/plugins/feedwordpress/feedwordpress-elements.js
@@ -62,7 +62,7 @@ fwpList = {
 
 		if ( !s ) { return false; }
 
-		if ( !e.is("[class^=add:" + list.id + ":]") ) { return !fwpList.add.call( list, e, s ); }
+		if ( !e.is('[class^="add:' + list.id + ':"]') ) { return !fwpList.add.call( list, e, s ); }
 
 		if ( !s.element ) { return true; }
 
@@ -91,6 +91,7 @@ fwpList = {
 			if ( true === res ) { return true; }
 
 			jQuery.each( res.responses, function() {
+					// FIXME: Causes ownerDocument is undefined breakage in WP3.2
 				fwpList.add.call( list, this.data, $.extend( {}, s, { // this.firstChild.nodevalue
 					pos: this.position || 0,
 					id: this.id || 0,
@@ -321,11 +322,11 @@ fwpList = {
 	process: function(el) {
 		var list = this;
 
-		$("[class^=add:" + list.id + ":]", el || null)
+		$('[class^="add:' + list.id + ':"]', el || null)
 			.filter('form').submit( function() { return list.fwpList.add(this); } ).end()
 			.not('form').click( function() { return list.fwpList.add(this); } );
-		$("[class^=delete:" + list.id + ":]", el || null).click( function() { return list.fwpList.del(this); } );
-		$("[class^=dim:" + list.id + ":]", el || null).click( function() { return list.fwpList.dim(this); } );
+		$('[class^="delete:' + list.id + ':"]', el || null).click( function() { return list.fwpList.del(this); } );
+		$('[class^="dim:' + list.id + ':"]', el || null).click( function() { return list.fwpList.dim(this); } );
 	},
 
 	recolor: function() {
diff --git a/wp-content/plugins/feedwordpress/feedwordpress.php b/wp-content/plugins/feedwordpress/feedwordpress.php
index 32024cff123501a05fdb7af004c70dda5db7d957..310f9bd8f8e96ed831e21a2f5bb75a7b9063f67c 100644
--- a/wp-content/plugins/feedwordpress/feedwordpress.php
+++ b/wp-content/plugins/feedwordpress/feedwordpress.php
@@ -3,7 +3,7 @@
 Plugin Name: FeedWordPress
 Plugin URI: http://feedwordpress.radgeek.com/
 Description: simple and flexible Atom/RSS syndication for WordPress
-Version: 2011.0211.2
+Version: 2011.0721
 Author: Charles Johnson
 Author URI: http://radgeek.com/
 License: GPL
@@ -11,7 +11,7 @@ License: GPL
 
 /**
  * @package FeedWordPress
- * @version 2011.0211.2
+ * @version 2011.0721
  */
 
 # This uses code derived from:
@@ -34,7 +34,7 @@ License: GPL
 
 # -- Don't change these unless you know what you're doing...
 
-define ('FEEDWORDPRESS_VERSION', '2011.0211.2');
+define ('FEEDWORDPRESS_VERSION', '2011.0721');
 define ('FEEDWORDPRESS_AUTHOR_CONTACT', 'http://radgeek.com/contact');
 
 if (!defined('FEEDWORDPRESS_BLEG')) :
@@ -109,14 +109,19 @@ if (!function_exists('wp_insert_user')) :
 	require_once (ABSPATH . WPINC . '/registration.php'); // for wp_insert_user
 endif;
 
-require_once(dirname(__FILE__) . '/admin-ui.php');
-require_once(dirname(__FILE__) . '/feedwordpresssyndicationpage.class.php');
-require_once(dirname(__FILE__) . '/compatability.php'); // LEGACY API: Replicate or mock up functions for legacy support purposes
-
-require_once(dirname(__FILE__) . '/syndicatedpost.class.php');
-require_once(dirname(__FILE__) . '/syndicatedlink.class.php');
-require_once(dirname(__FILE__) . '/feedwordpresshtml.class.php');
-require_once(dirname(__FILE__) . '/feedwordpress-content-type-sniffer.class.php');
+$dir = dirname(__FILE__); 
+require_once("${dir}/admin-ui.php");
+require_once("${dir}/feedwordpresssyndicationpage.class.php");
+require_once("${dir}/compatability.php"); // Legacy API             
+require_once("${dir}/syndicatedpost.class.php");
+require_once("${dir}/syndicatedlink.class.php");
+require_once("${dir}/feedwordpresshtml.class.php");
+require_once("${dir}/feedwordpress-content-type-sniffer.class.php");
+require_once("${dir}/inspectpostmeta.class.php");
+require_once("${dir}/syndicationdataqueries.class.php");
+require_once("${dir}/feedwordpress_file.class.php");
+require_once("${dir}/feedwordpress_parser.class.php");
+require_once("${dir}/feedwordpressrpc.class.php");
 
 // Magic quotes are just about the stupidest thing ever.
 if (is_array($_POST)) :
@@ -224,11 +229,11 @@ if (!FeedWordPress::needs_upgrade()) : // only work if the conditions are safe!
 	$feedwordpress = new FeedWordPress;
 
 	# Cron-less auto-update. Hooray!
-	$autoUpdateHook = get_option('feedwordpress_automatic_updates');
-	if ($autoUpdateHook != 'init') :
-		$autoUpdateHook = 'shutdown';
+	$autoUpdateHook = $feedwordpress->automatic_update_hook();
+	if (!is_null($autoUpdateHook)) :
+		add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
 	endif;
-	add_action($autoUpdateHook, array(&$feedwordpress, 'auto_update'));
+	
 	add_action('init', array(&$feedwordpress, 'init'));
 	add_action('shutdown', array(&$feedwordpress, 'email_diagnostic_log'));
 	add_action('wp_dashboard_setup', array(&$feedwordpress, 'dashboard_setup'));
@@ -810,6 +815,9 @@ function fwp_publish_post_hook ($post_id) {
 
 	function feedwordpress_add_post_edit_controls () {
 		add_meta_box('feedwordpress-post-controls', __('Syndication'), 'feedwordpress_post_edit_controls', 'post', 'side', 'high');
+		if (FeedWordPress::diagnostic_on('syndicated_posts:static_meta_data')) :
+			$GLOBALS['inspectPostMeta'] = new InspectPostMeta;
+		endif;
 	} // function FeedWordPress::postEditControls
 	
 	function feedwordpress_post_edit_controls () {
@@ -975,6 +983,13 @@ class FeedWordPress {
 		if (!is_null($uri) and $uri != '*') :
 			$uri = trim($uri);
 		else : // Update all
+			if ($this->update_hooked) :
+				$diag = $this->update_hooked;
+			else :
+				$diag = 'Initiating a MANUAL check-in on the update schedule at '.date('r', time());
+			endif;
+			$this->diagnostic('update_schedule:check', $diag);
+
 			update_option('feedwordpress_last_update_all', time());
 		endif;
 
@@ -984,6 +999,8 @@ class FeedWordPress {
 			$crash_ts = $this->crash_ts();
 		endif;
 
+		$max_polls = apply_filters('feedwordpress_polls_per_update', get_option('feedwordpress_polls_per_update', 10), $uri);
+		
 		// Randomize order for load balancing purposes
 		$feed_set = $this->feeds;
 		shuffle($feed_set);
@@ -991,12 +1008,20 @@ class FeedWordPress {
 		$feed_set = apply_filters('feedwordpress_update_feeds', $feed_set, $uri);
 
 		// Loop through and check for new posts
-		$delta = NULL;
+		$delta = NULL; $remaining = $max_polls;
 		foreach ($feed_set as $feed) :
-			if (!is_null($crash_ts) and (time() > $crash_ts)) : // Check whether we've exceeded the time limit
+
+			// Has this process overstayed its welcome?
+			if (
+				// Over time limit?
+				(!is_null($crash_ts) and (time() > $crash_ts))
+				
+				// Over feed count?
+				or ($remaining == 0) 
+			) :
 				break;
 			endif;
-
+			
 			$pinged_that = (is_null($uri) or ($uri=='*') or in_array($uri, array($feed->uri(), $feed->homepage())));
 
 			if (!is_null($uri)) : // A site-specific ping always updates
@@ -1010,6 +1035,8 @@ class FeedWordPress {
 			endif;
 
 			if ($pinged_that and $timely) :
+				$remaining = $remaining - 1;
+
 				do_action('feedwordpress_check_feed', $feed->settings);
 				$start_ts = time();
 				$added = $feed->poll($crash_ts);
@@ -1037,12 +1064,79 @@ class FeedWordPress {
 		return $crash_ts;
 	}
 	
+	function secret_key () {
+		$secret = get_option('feedwordpress_secret_key', false);
+		if (!$secret) : // Generate random key.
+			$secret = substr(md5(uniqid(microtime())), 0, 6);
+			update_option('feedwordpress_secret_key', $secret);
+		endif;
+		return $secret;
+	}
+	
+	function has_secret () {
+		return ($this->by_request('feedwordpress_key', $this->secret_key()));
+	}
+
+	// Utility function so I don't have to repeat myself w/ 1,000,003 isset()'s
+	function by_request ($param, $eq = NULL) {
+		$match = false;
+		if (isset($_REQUEST[$param])) :
+			$match = (is_null($eq) ? $_REQUEST[$param] : ($eq==$_REQUEST[$param]));
+		endif;
+		return $match;
+	}
+	
+	var $update_hooked = NULL;
+	function automatic_update_hook ($params = array()) {
+		$params = wp_parse_args($params, array( // Defaults
+			'setting only' => false,
+		));
+		$hook = get_option('feedwordpress_automatic_updates', NULL);
+		$method = 'FeedWordPress option';
+
+		// Allow for forced behavior in testing.
+		if (
+			!$params['setting only']
+			and $this->has_secret()
+			and $this->by_request('automatic_update')
+		) :
+			$hook = $_REQUEST['automatic_update'];
+			$method = 'URL parameter';
+		endif;
+		
+		$exact = $hook; // Before munging
+		
+		if (!!$hook) :
+			if ($hook != 'init') : // Constrain values.
+				$hook = 'shutdown';
+			endif;
+		endif;
+		
+		if ($hook) :
+			$this->update_hooked = "Initiating an AUTOMATIC CHECK FOR UPDATES ON PAGE LOAD ".$hook." due to ".$method." = ".trim($this->val($exact));
+		endif;
+		
+		return $hook; 
+	}
+	function last_update_all () {
+		$last = get_option('feedwordpress_last_update_all');
+		if ($this->has_secret() and $this->by_request('automatic_update')) :
+			$last = 1; // A long, long time ago.
+		elseif ($this->has_secret() and $this->by_request('last_update_all')) :
+			$last = $_REQUEST['last_update_all'];
+		endif;
+		return $last;
+	}
+	function force_update_all () {
+		return ($this->has_secret() and $this->by_request('force_update_feeds'));
+	}
+	
 	function stale () {
-		if (get_option('feedwordpress_automatic_updates')) :
+		if (!is_null($this->automatic_update_hook())) :
 			// Do our best to avoid possible simultaneous
 			// updates by getting up-to-the-minute settings.
 			
-			$last = get_option('feedwordpress_last_update_all');
+			$last = $this->last_update_all();
 		
 			// If we haven't updated all yet, give it a time window
 			if (false === $last) :
@@ -1055,11 +1149,11 @@ class FeedWordPress {
 				if (false === $freshness) : // Use default
 					$freshness = FEEDWORDPRESS_FRESHNESS_INTERVAL;
 				endif;
-				$ret = ( (time() - $last) > $freshness);
-
-			 // This should never happen.
+				$ret = ( (time() - $last) > $freshness );
+			
+			// This should never happen.
 			else :
-				FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__);
+				FeedWordPress::critical_bug('FeedWordPress::stale::last', $last, __LINE__, __FILE__);
 			endif;
 
 		else :
@@ -1139,6 +1233,8 @@ class FeedWordPress {
 
 		// Explicit update request in the HTTP request (e.g. from a cron job)
 		if ($this->update_requested()) :
+			$this->update_hooked = "Initiating a CRON JOB CHECK-IN ON UPDATE SCHEDULE due to URL parameter = ".trim($this->val($_REQUEST['update_feedwordpress']));
+
 			$this->update($this->update_requested_url());
 			
 			if (FEEDWORDPRESS_DEBUG and count($wpdb->queries) > 0) :
@@ -1182,10 +1278,7 @@ class FeedWordPress {
 	} /* FeedWordPress::clear_cache_requested() */
 
 	function update_requested () {
-		return (
-			isset($_REQUEST['update_feedwordpress'])
-			and $_REQUEST['update_feedwordpress']
-		);
+		return FeedWordPress::by_request('update_feedwordpress');
 	} // FeedWordPress::update_requested()
 
 	function update_requested_url () {
@@ -1502,7 +1595,6 @@ class FeedWordPress {
 		$feed->set_cache_class($cache_class);
 		$feed->set_timeout($timeout);
 		
-		//$feed->set_file_class('WP_SimplePie_File');
 		$feed->set_content_type_sniffer_class($sniffer_class);
 		$feed->set_file_class($file_class);
 		$feed->set_parser_class($parser_class);
@@ -1577,23 +1669,29 @@ class FeedWordPress {
 	}
 
 	# Internal debugging functions
-	function critical_bug ($varname, $var, $line) {
+	function critical_bug ($varname, $var, $line, $file = NULL) {
 		global $wp_version;
-
-		echo '<p>There may be a bug in FeedWordPress. Please <a href="'.FEEDWORDPRESS_AUTHOR_CONTACT.'">contact the author</a> and paste the following information into your e-mail:</p>';
-		echo "\n<plaintext>";
-		echo "Triggered at line # ".$line."\n";
-		echo "FeedWordPress version: ".FEEDWORDPRESS_VERSION."\n";
-		echo "WordPress version: {$wp_version}\n";
-		echo "PHP version: ".phpversion()."\n";
-		echo "\n";
-		echo $varname.": "; var_dump($var); echo "\n";
+		
+		if (!is_null($file)) :
+			$location = "line # ${line} of ".basename($file);
+		else :
+			$location = "line # ${line}";
+		endif;
+		
+		print '<p><strong>Critical error:</strong> There may be a bug in FeedWordPress. Please <a href="'.FEEDWORDPRESS_AUTHOR_CONTACT.'">contact the author</a> and paste the following information into your e-mail:</p>';
+		print "\n<plaintext>";
+		print "Triggered at ${location}\n";
+		print "FeedWordPress: ".FEEDWORDPRESS_VERSION."\n";
+		print "WordPress:     {$wp_version}\n";
+		print "PHP:           ".phpversion()."\n";
+		print "Error data:    ";
+		print  $varname.": "; var_dump($var); echo "\n";
 		die;
 	}
 	
-	function noncritical_bug ($varname, $var, $line) {
+	function noncritical_bug ($varname, $var, $line, $file = NULL) {
 		if (FEEDWORDPRESS_DEBUG) : // halt only when we are doing debugging
-			FeedWordPress::critical_bug($varname, $var, $line);
+			FeedWordPress::critical_bug($varname, $var, $line, $file);
 		endif;
 	}
 	
@@ -1625,7 +1723,9 @@ class FeedWordPress {
 			foreach ($output as $method) :
 				switch ($method) :
 				case 'echo' :
-					echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.$out."</pre></div>";
+					if (!FeedWordPress::update_requested()) :
+						echo "<div><pre><strong>Diag".str_repeat('====', $diagnostic_nesting-1).'|</strong> '.$out."</pre></div>";
+					endif;
 					break;
 				case 'echo_in_cronjob' :
 					if (FeedWordPress::update_requested()) :
@@ -1660,14 +1760,36 @@ class FeedWordPress {
 		update_option('feedwordpress_diagnostics_log', $dlog);		
 	} /* FeedWordPress::diagnostic () */
 	
+	function email_diagnostics_override () {
+		return ($this->has_secret() and isset($_REQUEST['feedwordpress_email_diagnostics']) and !!$_REQUEST['feedwordpress_email_diagnostics']);
+	}
+	function has_emailed_diagnostics ($dlog) {
+		$ret = false;
+		if ($this->email_diagnostics_override()
+		or (isset($dlog['schedule']) and isset($dlog['schedule']['last']))) :
+			$ret = true;
+		endif;
+		return $ret;
+	}
+	function ready_to_email_diagnostics ($dlog) {
+		$ret = false;
+		if ($this->email_diagnostics_override()
+		or (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq']))) :
+			$ret = true;
+		endif;
+		return $ret;
+	}
+	
 	function email_diagnostic_log () {
 		$dlog = get_option('feedwordpress_diagnostics_log', array());
 		
-		if (isset($dlog['schedule']) and isset($dlog['schedule']['last'])) :
-			if (time() > ($dlog['schedule']['last'] + $dlog['schedule']['freq'])) :
+		if ($this->has_emailed_diagnostics($dlog)) :
+			if ($this->ready_to_email_diagnostics($dlog)) :
 				// No news is good news; only send if
 				// there are some messages to send.
 				$body = NULL;
+				if (!isset($dlog['mesg'])) : $dlog['mesg'] = array(); endif;
+				
 				foreach ($dlog['mesg'] as $sect => $mesgs) :
 					if (count($mesgs) > 0) :
 						if (is_null($body)) : $body = ''; endif;
@@ -1698,9 +1820,10 @@ class FeedWordPress {
 					endif;
 				endforeach;
 				
+				$body = apply_filters('feedwordpress_diagnostic_email_body', $body, $dlog);
 				if (!is_null($body)) :
 					$home = feedwordpress_display_url(get_bloginfo('url'));
-					$subj = $home . " syndication issues for ".date('j-M-y', time());
+					$subj = apply_filters('feedwordpress_diagnostic_email_subject', $home . " syndication issues", $dlog);
 					$agent = 'FeedWordPress '.FEEDWORDPRESS_VERSION;
 					$body = <<<EOMAIL
 <html>
@@ -1823,344 +1946,8 @@ EOMAIL;
 	}
 } // class FeedWordPress
 
-class FeedWordPress_File extends WP_SimplePie_File {
-	function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
-		WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
-
-		// SimplePie makes a strongly typed check against integers with
-		// this, but WordPress puts a string in. Which causes caching
-		// to break and fall on its ass when SimplePie is getting a 304,
-		// but doesn't realize it because this member is "304" instead.
-		$this->status_code = (int) $this->status_code;
-	}
-} /* class FeedWordPress_File () */
-
-class FeedWordPress_Parser extends SimplePie_Parser {
-	function parse (&$data, $encoding) {
-		// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
-		if (strtoupper($encoding) === 'US-ASCII')
-		{
-			$this->encoding = 'UTF-8';
-		}
-		else
-		{
-			$this->encoding = $encoding;
-		}
-
-		// Strip BOM:
-		// UTF-32 Big Endian BOM
-		if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
-		{
-			$data = substr($data, 4);
-		}
-		// UTF-32 Little Endian BOM
-		elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
-		{
-			$data = substr($data, 4);
-		}
-		// UTF-16 Big Endian BOM
-		elseif (substr($data, 0, 2) === "\xFE\xFF")
-		{
-			$data = substr($data, 2);
-		}
-		// UTF-16 Little Endian BOM
-		elseif (substr($data, 0, 2) === "\xFF\xFE")
-		{
-			$data = substr($data, 2);
-		}
-		// UTF-8 BOM
-		elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
-		{
-			$data = substr($data, 3);
-		}
-
-		if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
-		{
-			$declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
-			if ($declaration->parse())
-			{
-				$data = substr($data, $pos + 2);
-				$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
-			}
-			else
-			{
-				$this->error_string = 'SimplePie bug! Please report this!';
-				return false;
-			}
-		}
-
-		$return = true;
-
-		static $xml_is_sane = null;
-		if ($xml_is_sane === null)
-		{
-			$parser_check = xml_parser_create();
-			xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
-			xml_parser_free($parser_check);
-			$xml_is_sane = isset($values[0]['value']);
-		}
-
-		// Create the parser
-		if ($xml_is_sane)
-		{
-			$xml = xml_parser_create_ns($this->encoding, $this->separator);
-			xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
-			xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
-			xml_set_object($xml, $this);
-			xml_set_character_data_handler($xml, 'cdata');
-			xml_set_element_handler($xml, 'tag_open', 'tag_close');
-			xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
-
-			// Parse!
-			if (!xml_parse($xml, $data, true))
-			{
-				$this->error_code = xml_get_error_code($xml);
-				$this->error_string = xml_error_string($this->error_code);
-				$return = false;
-			}
-
-			$this->current_line = xml_get_current_line_number($xml);
-			$this->current_column = xml_get_current_column_number($xml);
-			$this->current_byte = xml_get_current_byte_index($xml);
-			xml_parser_free($xml);
-
-			return $return;
-		}
-		else
-		{
-			libxml_clear_errors();
-			$xml =& new XMLReader();
-			$xml->xml($data);
-			while (@$xml->read())
-			{
-				switch ($xml->nodeType)
-				{
-
-					case constant('XMLReader::END_ELEMENT'):
-						if ($xml->namespaceURI !== '')
-						{
-							$tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
-						}
-						else
-						{
-							$tagName = $xml->localName;
-						}
-						$this->tag_close(null, $tagName);
-						break;
-					case constant('XMLReader::ELEMENT'):
-						$empty = $xml->isEmptyElement;
-						if ($xml->namespaceURI !== '')
-						{
-							$tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
-						}
-						else
-						{
-							$tagName = $xml->localName;
-						}
-						$attributes = array();
-						while ($xml->moveToNextAttribute())
-						{
-							if ($xml->namespaceURI !== '')
-							{
-								$attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
-							}
-							else
-							{
-								$attrName = $xml->localName;
-							}
-							$attributes[$attrName] = $xml->value;
-						}
-						
-						foreach ($attributes as $attr => $value) :
-							list($ns, $local) = $this->split_ns($attr);
-							if ($ns=='http://www.w3.org/2000/xmlns/') :
-								if ('xmlns' == $local) : $local = false; endif;
-								$this->start_xmlns(null, $local, $value);
-							endif;
-						endforeach;
-						
-						$this->tag_open(null, $tagName, $attributes);
-						if ($empty)
-						{
-							$this->tag_close(null, $tagName);
-						}
-						break;
-					case constant('XMLReader::TEXT'):
-
-					case constant('XMLReader::CDATA'):
-						$this->cdata(null, $xml->value);
-						break;
-				}
-			}
-			if ($error = libxml_get_last_error())
-			{
-				$this->error_code = $error->code;
-				$this->error_string = $error->message;
-				$this->current_line = $error->line;
-				$this->current_column = $error->column;
-				return false;
-			}
-			else
-			{
-				return true;
-			}
-		}
-	} /* FeedWordPress_Parser::parse() */
-	
-	var $xmlns_stack = array();
-	var $xmlns_current = array();
-	function tag_open ($parser, $tag, $attributes) {
-		$ret = parent::tag_open($parser, $tag, $attributes);
-		if ($this->current_xhtml_construct < 0) :
-			$this->data['xmlns'] = $this->xmlns_current;
-			$this->xmlns_stack[] = $this->xmlns_current;
-		endif;
-		return $ret;
-	}
-	
-	function tag_close($parser, $tag) {
-		if ($this->current_xhtml_construct < 0) :
-			$this->xmlns_current = array_pop($this->xmlns_stack);
-		endif;
-		$ret = parent::tag_close($parser, $tag);
-		return $ret;
-	}
-	
-	function start_xmlns ($parser, $prefix, $uri) {
-		if (!$prefix) :
-			$prefix = '';
-		endif;
-		if ($this->current_xhtml_construct < 0) :
-			$this->xmlns_current[$prefix] = $uri;
-		endif;
-		return true;
-	} /* FeedWordPress_Parser::start_xmlns() */
-}
-
 $feedwordpress_admin_footer = array();
 
-################################################################################
-## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
-################################################################################
-
-class FeedWordPressRPC {
-	function FeedWordPressRPC () {
-		add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
-	}
-	
-	function xmlrpc_methods ($args = array()) {
-		$args['weblogUpdates.ping'] = array(&$this, 'ping');
-		$args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
-		$args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
-		$args['feedwordpress.delete'] = array(&$this, 'delete');
-		$args['feedwordpress.nuke'] = array(&$this, 'nuke');
-		return $args;
-	}
-	
-	function ping ($args) {
-		global $feedwordpress;
-		
-		$delta = @$feedwordpress->update($args[1]);
-		if (is_null($delta)):
-			return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
-		else:
-			$mesg = array();
-			if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
-			if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
-	
-			return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
-		endif;
-	}
-	
-	function validate (&$args) {
-		global $wp_xmlrpc_server;
-
-		// First two params are username/password
-		$username = $wp_xmlrpc_server->escape(array_shift($args));
-		$password = $wp_xmlrpc_server->escape(array_shift($args));
-
-		$ret = array();
-		if ( !$user = $wp_xmlrpc_server->login($username, $password) ) :
-			$ret = $wp_xmlrpc_server->error;
-		elseif (!current_user_can('manage_links')) :
-			$ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.');
-		endif;
-		return $ret;
-	}
-
-	function subscribe ($args) {
-		$ret = $this->validate($args);
-		if (is_array($ret)) : // Success
-			// The remaining params are feed URLs
-			foreach ($args as $arg) :
-				$finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1);
-				$feeds = array_values(array_unique($finder->find()));
-				
-				if (count($feeds) > 0) :
-					$link_id = FeedWordPress::syndicate_link(
-						/*title=*/ feedwordpress_display_url($feeds[0]),
-						/*homepage=*/ $feeds[0],
-						/*feed=*/ $feeds[0]
-					);
-					$ret[] = array(
-						'added',
-						$feeds[0],
-						$arg,
-					);
-				else :
-					$ret[] = array(
-						'error',
-						$arg
-					);
-				endif;
-			endforeach;
-		endif;
-		return $ret;
-	} /* FeedWordPressRPC::subscribe () */
-	
-	function unsubscribe ($method, $args) {
-		$ret = $this->validate($args);
-		if (is_array($ret)) : // Success
-			// The remaining params are feed URLs
-			foreach ($args as $arg) :
-				$link_id = FeedWordPress::find_link($arg);
-				
-				if (!$link_id) :
-					$link_id = FeedWordPress::find_link($arg, 'link_url');
-				endif;
-				
-				if ($link_id) :
-					$link = new SyndicatedLink($link_id);
-					
-					$link->{$method}();
-					$ret[] = array(
-						'deactivated',
-						$arg,
-					);
-				else :
-					$ret[] = array(
-						'error',
-						$arg,
-					);
-				endif;
-			endforeach;
-		endif;
-		return $ret;
-	} /* FeedWordPress::unsubscribe () */
-	
-	function deactivate ($args) {
-		return $this->unsubscribe('deactivate', $args);
-	} /* FeedWordPressRPC::deactivate () */
-	
-	function delete ($args) {
-		return $this->unsubscribe('delete', $args);
-	} /* FeedWordPressRPC::delete () */
-	
-	function nuke ($args) {
-		return $this->unsubscribe('nuke', $args);
-	} /* FeedWordPressRPC::nuke () */
-} /* class FeedWordPressRPC */
-
 // take your best guess at the realname and e-mail, given a string
 define('FWP_REGEX_EMAIL_ADDY', '([^@"(<\s]+@[^"@(<\s]+\.[^"@(<\s]+)');
 define('FWP_REGEX_EMAIL_NAME', '("([^"]*)"|([^"<(]+\S))');
diff --git a/wp-content/plugins/feedwordpress/feedwordpress_file.class.php b/wp-content/plugins/feedwordpress/feedwordpress_file.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..70a9edffe2d889546cb4dc0ea643e3d58a01e910
--- /dev/null
+++ b/wp-content/plugins/feedwordpress/feedwordpress_file.class.php
@@ -0,0 +1,21 @@
+<?php
+class FeedWordPress_File extends WP_SimplePie_File {
+	function FeedWordPress_File ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
+		self::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+	}
+	
+	function __construct ($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false) {
+		if (is_callable(array('WP_SimplePie_File', 'WP_SimplePie_File'))) : // PHP 4 idiom
+			WP_SimplePie_File::WP_SimplePie_File($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+		else : // PHP 5+
+			parent::__construct($url, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+		endif;
+		
+		// SimplePie makes a strongly typed check against integers with
+		// this, but WordPress puts a string in. Which causes caching
+		// to break and fall on its ass when SimplePie is getting a 304,
+		// but doesn't realize it because this member is "304" instead.
+		$this->status_code = (int) $this->status_code;
+	}
+} /* class FeedWordPress_File () */
+
diff --git a/wp-content/plugins/feedwordpress/feedwordpress_parser.class.php b/wp-content/plugins/feedwordpress/feedwordpress_parser.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..49c2239bffcdb543c2ff7ee4a571422624f8a418
--- /dev/null
+++ b/wp-content/plugins/feedwordpress/feedwordpress_parser.class.php
@@ -0,0 +1,203 @@
+<?php
+class FeedWordPress_Parser extends SimplePie_Parser {
+	function parse (&$data, $encoding) {
+		// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
+		if (strtoupper($encoding) === 'US-ASCII')
+		{
+			$this->encoding = 'UTF-8';
+		}
+		else
+		{
+			$this->encoding = $encoding;
+		}
+
+		// Strip BOM:
+		// UTF-32 Big Endian BOM
+		if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+		{
+			$data = substr($data, 4);
+		}
+		// UTF-32 Little Endian BOM
+		elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+		{
+			$data = substr($data, 4);
+		}
+		// UTF-16 Big Endian BOM
+		elseif (substr($data, 0, 2) === "\xFE\xFF")
+		{
+			$data = substr($data, 2);
+		}
+		// UTF-16 Little Endian BOM
+		elseif (substr($data, 0, 2) === "\xFF\xFE")
+		{
+			$data = substr($data, 2);
+		}
+		// UTF-8 BOM
+		elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+		{
+			$data = substr($data, 3);
+		}
+
+		if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
+		{
+			$declaration =& new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+			if ($declaration->parse())
+			{
+				$data = substr($data, $pos + 2);
+				$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
+			}
+			else
+			{
+				$this->error_string = 'SimplePie bug! Please report this!';
+				return false;
+			}
+		}
+
+		$return = true;
+
+		static $xml_is_sane = null;
+		if ($xml_is_sane === null)
+		{
+			$parser_check = xml_parser_create();
+			xml_parse_into_struct($parser_check, '<foo>&amp;</foo>', $values);
+			xml_parser_free($parser_check);
+			$xml_is_sane = isset($values[0]['value']);
+		}
+
+		// Create the parser
+		if ($xml_is_sane)
+		{
+			$xml = xml_parser_create_ns($this->encoding, $this->separator);
+			xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
+			xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
+			xml_set_object($xml, $this);
+			xml_set_character_data_handler($xml, 'cdata');
+			xml_set_element_handler($xml, 'tag_open', 'tag_close');
+			xml_set_start_namespace_decl_handler($xml, 'start_xmlns');
+
+			// Parse!
+			if (!xml_parse($xml, $data, true))
+			{
+				$this->error_code = xml_get_error_code($xml);
+				$this->error_string = xml_error_string($this->error_code);
+				$return = false;
+			}
+
+			$this->current_line = xml_get_current_line_number($xml);
+			$this->current_column = xml_get_current_column_number($xml);
+			$this->current_byte = xml_get_current_byte_index($xml);
+			xml_parser_free($xml);
+
+			return $return;
+		}
+		else
+		{
+			libxml_clear_errors();
+			$xml =& new XMLReader();
+			$xml->xml($data);
+			while (@$xml->read())
+			{
+				switch ($xml->nodeType)
+				{
+
+					case constant('XMLReader::END_ELEMENT'):
+						if ($xml->namespaceURI !== '')
+						{
+							$tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
+						}
+						else
+						{
+							$tagName = $xml->localName;
+						}
+						$this->tag_close(null, $tagName);
+						break;
+					case constant('XMLReader::ELEMENT'):
+						$empty = $xml->isEmptyElement;
+						if ($xml->namespaceURI !== '')
+						{
+							$tagName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
+						}
+						else
+						{
+							$tagName = $xml->localName;
+						}
+						$attributes = array();
+						while ($xml->moveToNextAttribute())
+						{
+							if ($xml->namespaceURI !== '')
+							{
+								$attrName = "{$xml->namespaceURI}{$this->separator}{$xml->localName}";
+							}
+							else
+							{
+								$attrName = $xml->localName;
+							}
+							$attributes[$attrName] = $xml->value;
+						}
+						
+						foreach ($attributes as $attr => $value) :
+							list($ns, $local) = $this->split_ns($attr);
+							if ($ns=='http://www.w3.org/2000/xmlns/') :
+								if ('xmlns' == $local) : $local = false; endif;
+								$this->start_xmlns(null, $local, $value);
+							endif;
+						endforeach;
+						
+						$this->tag_open(null, $tagName, $attributes);
+						if ($empty)
+						{
+							$this->tag_close(null, $tagName);
+						}
+						break;
+					case constant('XMLReader::TEXT'):
+
+					case constant('XMLReader::CDATA'):
+						$this->cdata(null, $xml->value);
+						break;
+				}
+			}
+			if ($error = libxml_get_last_error())
+			{
+				$this->error_code = $error->code;
+				$this->error_string = $error->message;
+				$this->current_line = $error->line;
+				$this->current_column = $error->column;
+				return false;
+			}
+			else
+			{
+				return true;
+			}
+		}
+	} /* FeedWordPress_Parser::parse() */
+	
+	var $xmlns_stack = array();
+	var $xmlns_current = array();
+	function tag_open ($parser, $tag, $attributes) {
+		$ret = parent::tag_open($parser, $tag, $attributes);
+		if ($this->current_xhtml_construct < 0) :
+			$this->data['xmlns'] = $this->xmlns_current;
+			$this->xmlns_stack[] = $this->xmlns_current;
+		endif;
+		return $ret;
+	}
+	
+	function tag_close($parser, $tag) {
+		if ($this->current_xhtml_construct < 0) :
+			$this->xmlns_current = array_pop($this->xmlns_stack);
+		endif;
+		$ret = parent::tag_close($parser, $tag);
+		return $ret;
+	}
+	
+	function start_xmlns ($parser, $prefix, $uri) {
+		if (!$prefix) :
+			$prefix = '';
+		endif;
+		if ($this->current_xhtml_construct < 0) :
+			$this->xmlns_current[$prefix] = $uri;
+		endif;
+		return true;
+	} /* FeedWordPress_Parser::start_xmlns() */
+}
+
diff --git a/wp-content/plugins/feedwordpress/feedwordpressrpc.class.php b/wp-content/plugins/feedwordpress/feedwordpressrpc.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..ead601c558a73075fe0b31037beb2477fbe0ff56
--- /dev/null
+++ b/wp-content/plugins/feedwordpress/feedwordpressrpc.class.php
@@ -0,0 +1,123 @@
+<?php
+################################################################################
+## XML-RPC HOOKS: accept XML-RPC update pings from Contributors ################
+################################################################################
+
+class FeedWordPressRPC {
+	function FeedWordPressRPC () {
+		add_filter('xmlrpc_methods', array(&$this, 'xmlrpc_methods'));
+	}
+	
+	function xmlrpc_methods ($args = array()) {
+		$args['weblogUpdates.ping'] = array(&$this, 'ping');
+		$args['feedwordpress.subscribe'] = array(&$this, 'subscribe');
+		$args['feedwordpress.deactivate'] = array(&$this, 'deactivate');
+		$args['feedwordpress.delete'] = array(&$this, 'delete');
+		$args['feedwordpress.nuke'] = array(&$this, 'nuke');
+		return $args;
+	}
+	
+	function ping ($args) {
+		global $feedwordpress;
+		
+		$delta = @$feedwordpress->update($args[1]);
+		if (is_null($delta)):
+			return array('flerror' => true, 'message' => "Sorry. I don't syndicate <$args[1]>.");
+		else:
+			$mesg = array();
+			if (isset($delta['new'])) { $mesg[] = ' '.$delta['new'].' new posts were syndicated'; }
+			if (isset($delta['updated'])) { $mesg[] = ' '.$delta['updated'].' existing posts were updated'; }
+	
+			return array('flerror' => false, 'message' => "Thanks for the ping.".implode(' and', $mesg));
+		endif;
+	}
+	
+	function validate (&$args) {
+		global $wp_xmlrpc_server;
+
+		// First two params are username/password
+		$username = $wp_xmlrpc_server->escape(array_shift($args));
+		$password = $wp_xmlrpc_server->escape(array_shift($args));
+
+		$ret = array();
+		if ( !$user = $wp_xmlrpc_server->login($username, $password) ) :
+			$ret = $wp_xmlrpc_server->error;
+		elseif (!current_user_can('manage_links')) :
+			$ret = new IXR_Error(401, 'Sorry, you cannot change the subscription list.');
+		endif;
+		return $ret;
+	}
+
+	function subscribe ($args) {
+		$ret = $this->validate($args);
+		if (is_array($ret)) : // Success
+			// The remaining params are feed URLs
+			foreach ($args as $arg) :
+				$finder = new FeedFinder($arg, /*verify=*/ false, /*fallbacks=*/ 1);
+				$feeds = array_values(array_unique($finder->find()));
+				
+				if (count($feeds) > 0) :
+					$link_id = FeedWordPress::syndicate_link(
+						/*title=*/ feedwordpress_display_url($feeds[0]),
+						/*homepage=*/ $feeds[0],
+						/*feed=*/ $feeds[0]
+					);
+					$ret[] = array(
+						'added',
+						$feeds[0],
+						$arg,
+					);
+				else :
+					$ret[] = array(
+						'error',
+						$arg
+					);
+				endif;
+			endforeach;
+		endif;
+		return $ret;
+	} /* FeedWordPressRPC::subscribe () */
+	
+	function unsubscribe ($method, $args) {
+		$ret = $this->validate($args);
+		if (is_array($ret)) : // Success
+			// The remaining params are feed URLs
+			foreach ($args as $arg) :
+				$link_id = FeedWordPress::find_link($arg);
+				
+				if (!$link_id) :
+					$link_id = FeedWordPress::find_link($arg, 'link_url');
+				endif;
+				
+				if ($link_id) :
+					$link = new SyndicatedLink($link_id);
+					
+					$link->{$method}();
+					$ret[] = array(
+						'deactivated',
+						$arg,
+					);
+				else :
+					$ret[] = array(
+						'error',
+						$arg,
+					);
+				endif;
+			endforeach;
+		endif;
+		return $ret;
+	} /* FeedWordPress::unsubscribe () */
+	
+	function deactivate ($args) {
+		return $this->unsubscribe('deactivate', $args);
+	} /* FeedWordPressRPC::deactivate () */
+	
+	function delete ($args) {
+		return $this->unsubscribe('delete', $args);
+	} /* FeedWordPressRPC::delete () */
+	
+	function nuke ($args) {
+		return $this->unsubscribe('nuke', $args);
+	} /* FeedWordPressRPC::nuke () */
+} /* class FeedWordPressRPC */
+
diff --git a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php
index 99b24d9dfb4980c7691b5143e0edf79b8e75c58b..71e060ef6f8ba32a5417cb1a9c5be91a9631271e 100644
--- a/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php
+++ b/wp-content/plugins/feedwordpress/feedwordpresssyndicationpage.class.php
@@ -93,7 +93,7 @@ class FeedWordPressSyndicationPage extends FeedWordPressAdminPage {
 						$update_set[] = $target->link_rss;
 					endforeach;
 				else : // This should never happen
-					FeedWordPress::critical_bug('fwp_syndication_manage_page::targets', $targets, __LINE__);
+					FeedWordPress::critical_bug('fwp_syndication_manage_page::targets', $targets, __LINE__, __FILE__);
 				endif;
 			elseif (!is_null(FeedWordPress::post('update_uri'))) :
 				$targets = FeedWordPress::post('update_uri');
diff --git a/wp-content/plugins/feedwordpress/inspectpostmeta.class.php b/wp-content/plugins/feedwordpress/inspectpostmeta.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..a53f4e2565d93d8f47d29badff9a3f5eb97f9aca
--- /dev/null
+++ b/wp-content/plugins/feedwordpress/inspectpostmeta.class.php
@@ -0,0 +1,71 @@
+<?php
+/*
+ * Inspect Post Meta
+ * Creates a post widget to help you inspect some meta fields for posts
+ * Version: 2010.1104
+ * Author: Charles Johnson
+ * Author URI: http://projects.radgeek.com
+*/
+
+class InspectPostMeta {
+	function InspectPostMeta ($in_hook = true) {
+		if (!$in_hook) :
+			add_action('admin_menu', array($this, 'add_meta_box'));
+		else :
+			$this->add_meta_box();
+		endif;
+	}
+	
+	function add_meta_box () {
+		add_meta_box(
+			/*id=*/ 'inspect_post_guid_box',
+			/*title=*/ 'Post GUID and Meta Data',
+			/*callback=*/ array($this, 'meta_box'),
+			/*page=*/ 'post',
+			/*context=*/ 'normal',
+			/*priority=*/ 'default'
+		);
+	}
+	
+	function meta_box () {
+		global $post;
+		?>
+		<table>
+		<tbody>
+		<tr>
+		<th style="text-align: left" scope="row">ID:</th>
+		<td><code><?php print esc_html($post->ID); ?></code></td>
+		</tr>
+
+		<tr>
+		<th style="text-align: left" scope="row">GUID:</th>
+		<td><code><?php print esc_html($post->guid); ?></code></td>
+		</tr>
+
+		<tr>
+		<th colspan="2" style="text-align: center"><h4>Custom Fields</h4></th>
+		</tr>
+
+		<?php
+		$custom = get_post_custom($post->ID);
+		if (count($custom) > 0) :
+			foreach ($custom as $key => $values) :
+				$idx = 1;
+				foreach ($values as $value) :
+					print "<tr><th style='text-align: left' scope='row'>".esc_html($key);
+					if ($idx > 1) :
+						print "[$idx]";
+					endif;
+					print ":</th> ";
+					print "<td><pre><code>".esc_html($value)."</code></pre>";
+					print "</td></tr>\n";
+					$idx++;
+				endforeach;
+			endforeach;
+		else :
+			print "<tr><td colspan='2'><p><em>No custom fields for this post.</em></p></td></tr>\n";
+		endif;
+		print "</table>\n";
+	} /* InspectPostMeta::meta_box() */
+} /* class InspectPostMeta */
+
diff --git a/wp-content/plugins/feedwordpress/readme.txt b/wp-content/plugins/feedwordpress/readme.txt
index 0219e2fe9a52275b49e7d9d5fdb6423b1ab5f8e6..97e4bbca30350ca02ccbd295a9fd08b0e4eeb3b0 100644
--- a/wp-content/plugins/feedwordpress/readme.txt
+++ b/wp-content/plugins/feedwordpress/readme.txt
@@ -3,8 +3,8 @@ Contributors: Charles Johnson
 Donate link: http://feedwordpress.radgeek.com/
 Tags: syndication, aggregation, feed, atom, rss
 Requires at least: 3.0
-Tested up to: 3.0.5
-Stable tag: 2011.0211.2
+Tested up to: 3.2
+Stable tag: 2011.0721
 
 FeedWordPress syndicates content from feeds you choose into your WordPress weblog. 
 
@@ -15,11 +15,12 @@ FeedWordPress syndicates content from feeds you choose into your WordPress weblo
 * License: GPL 2. See License below for copyright jots and tittles.
 
 FeedWordPress is an Atom/RSS aggregator for WordPress. It syndicates content
-from feeds that you choose into your WordPress weblog; if you syndicate several
-feeds then you can use WordPress's posts database and templating engine as the
-back-end of an aggregation ("planet") website. It was developed, originally,
-because I needed a more flexible replacement for [Planet][]
-to use at [Feminist Blogs][].
+from feeds that you choose into your WordPress weblog; the content it syndicates
+appears as a series of special posts in your WordPress posts database. If you
+syndicate several feeds then you can use WordPress's posts database and
+templating engine as the back-end of an aggregation ("planet") website. It was
+developed, originally, because I needed a more flexible replacement for
+[Planet][] to use at [Feminist Blogs][].
 
 [Planet]: http://www.planetplanet.org/
 [Feminist Blogs]: http://feministblogs.org/
@@ -93,6 +94,226 @@ outs, see the documentation at the [FeedWordPress project homepage][].
 
 == Changelog ==
 
+= 2011.0721 =
+
+*	BUGFIX: SERIOUS BUG CAUSING RARE UNEXPECTED DELETION OF PAGES AND OTHER
+	CONTENT. A bug in the guid-checking code for some rare kinds of guids could
+	cause content in the wp_posts table to seemingly disappear at random after
+	FeedWordPress updates.This most frequently but not exclusively affected
+	static pages. What actually happened is that in these rare cases the
+	existing static page was mistaken for an older version of the new incoming
+	syndicated post, which was then stored as a new revision of the original
+	page. The bug that caused these mistaken identities has been fixed.
+	
+*	BUGFIX: UNWANTED AUTOMATIC PAGE-LOAD-BASED UPDATES NO LONGER A NUISANCE.
+	Some users encountered a bug in which FeedWordPress would adopt an automatic
+	page-load-based update method, even if they had requested that it not do
+	so, and that it use a manual or cron job update method instead. The bug
+	causing this has been fixed, and page-load-based updates should no longer
+	trigger unless explicitly turned on.
+
+*	WP 3.2 USER INTERFACE COMPATIBILITY: POST TAGS BOX NOW WORKS AGAIN. The
+	release of WordPress 3.2 caused a breakage in the tags box which prevented
+	you from adding or removing tags under Syndication --> Categories & Tags.
+	(The breakage was the result of an incompatibility introduced by the new
+	release of jQuery.) This breakage has now been fixed, and the tags box
+	should work correctly again.
+
+*	FEED UPDATE SCHEDULING IMPROVEMENTS: UI. The Syndicated Sources table now
+	provides considerably more data to understand update scheduling, when
+	specific scheduling decisions are made because of, e.g., requests from the
+	feed producer.
+	
+* 	FEED UPDATE SCHEDULING IMPROVEMENTS: ENFORCEABLE "MINIMUM INTERVAL" SETTIN
+	TO SPACE OUT UPDATES. Some feeds request specific update schedules, using
+	standard elements such as sy:updateFrequency and rss:ttl. Normally,
+	FeedWordPress respects any scheduling requests that a feed makes -- if it
+	requests a longer gap between polls than what FWP would normally adopt, then
+	FWP slows down to meet the request. If it indicates a shorter gap than what
+	FWP would normally adopt, FWP speeds up and checks that feed for updates
+	more often than it normally would. Now, there should not be any way for user
+	settings to override an explicit slow-down request from the feed producer --
+	if producers indicate a particular update schedule, then polling the feed
+	more frequently than they request is considered abusive behavior. But
+	there's no reason why users should not be able -- if they so desire -- to
+	override speed-up requests, and poll a feed *less* frequently than the
+	indicated update schedule, if the FWP user wants to space update checkins
+	over a longer interval of time. Before, they could not do this: FWP always
+	sped up to meet the indicated update schedule. Now, they can do this, by
+	using the new "Minimum Interval" setting in Syndication --> Feeds &
+	Updates..
+	
+= 2011.0706 =
+
+*	WP 3.2 COMPATIBILITY: ELIMINATES FATAL ERROR "Call to undefined method
+    WP_SimplePie_File::WP_SimplePie_File() in
+    [...]/wp-content/plugins/feedwordpress/feedwordpress.php on line 1841." The
+    latest release of WordPress, version 3.2, has shifted the minimum
+    requirements up to PHP 5.2, and in line with the shift to PHP5 they have
+    rewritten a number of code segments that made use of now-obsolete PHP4
+    idioms. Unfortunately, this caused a fatal error whenever FeedWordPress
+    attempted to make use of the cache, since FWP's caching plugin was written
+    to match the older idiom. FeedWordPress has been updated to follow the new,
+    PHP5 idiom when possible, thus eliminating the fatal error.
+
+*	PERFORMANCE: The handling of queries to determine whether posts had been
+	previously syndicated produced some very slow queries (usually, but not
+	always, involving a scan over the MD5(post_guid) column of the table). The
+	code that prepares MySQL queries for previously-syndicated checks has been
+	revised to eliminate the MD5(post_guid) scan entirely, and to significantly
+	improve performance by eliminating other unnecessary clauses. 	
+
+*	BUGFIX: NO LONGER DESTROYS STICKY POSTS. Previous versions could destroy
+	(or, more precisely, replace the content of) sticky posts due to some
+	queries mashed together in unexpected ways by WordPress. Version 2011.0706
+	accounts for and eliminates the problem; your sticky posts should be safe
+	once again.
+
+*	BUGFIX: GUIDS CONTAINING MYSQL-ESCAPED CHARACTERS NO LONGER CAUSE DUPLICATE
+	POSTS TO APPEAR. One remaining source of duplicate post issues in 2011.0602
+	was guids that contained characters that needed to be escaped for MySQL,
+	such as single quotes and double quotes. The work-around for handling
+	filtered URIs has now been corrected to ensure that these do not cause
+	duplicate posts.
+
+= 2011.0602 =
+
+*	WP 3.1.3 COMPAT / BUGFIX: WHITESPACE IN GUIDS NO LONGER PRODUCES DUPLICATE
+	POSTS. The work-around for handling filtered URIs in guid elements has now
+	been extended to handle URIs that were filtered because of leading or
+	trailing whitespace, in addition to URIs that were filtered because of
+	unapproved schemes.
+	
+*	WP 3.1.3 COMPAT / BUGFIX: RELATIVE URLS IN GUIDS NO LONGER PRODUCE DUPLICATE
+	POSTS. The work-around for handling filtered URIs in guid elements has now
+	been extended to handle URIs that were altered without being filtered out
+	entirely (most commonly because a scheme was added to a relative URL).
+
+*	BUGFIX: UPDATES TO POST NO LONGER CAUSE DUPLICATE DRAFT VERSION TO APPEAR.
+	Under certain conditions in 2011.0531, an update to an existing post would
+	not be properly applied to the post itself, but rather would appear as a
+	duplicate post with Draft status. This bug has been eliminated, and updates
+	will now be properly inserted as revisions to the existing post.
+
+= 2011.0531 =
+
+*	WORDPRESS 3.1.3 COMPATIBILITY: DUPLICATE POSTS ISSUE FIXED. Due to
+	internal changes in the way that WordPress handles post guids in the
+	most recent release (3.1.3), many users experienced problems with many
+	duplicate posts appearing in rapid succession. (Specifically, this would
+	happen with any posts using tag: URL guids -- such as all the posts
+	coming from Blogger feeds or feeds from other Google services.) This
+	compatibility release of FeedWordPress eliminates the issue by working
+	around the new restrictions on tag: URLs.
+
+*	NEW AND IMPROVED DIAGNOSTICS: Syndication --> Diagnostics now contains some
+	new diagnostics settings useful for debugging problems with duplicate posts
+	(allowing you to easily view the guid of posts in the WordPress posts
+	database and allowing you to track the SQL used to check for existing
+	versions of a syndicated post).
+
+= 2011.0512 =
+
+*	DIAGNOSTICS IMPROVEMENTS; "THERE MAY BE A BUG IN FEEDWORDPRESS" CRITICAL
+	ERROR NOTICES ELIMINATED: This version includes some major improvements
+	to the Syndication --> Diagnostics section, which should aid in
+	troubleshooting difficulties with items failing to be imported, posts
+	failing to be properly inserted into the database, or updates failing to
+	be recorded. If you have been encountering critical error / bug notices
+	with a white screen and the message "THERE MAY BE A BUG IN
+	FEEDWORDPRESS," followed by an extraordinarily long dump of mostly
+	incomprehensible diagnostic information, you'll be happy to know that
+	the condition causing these notices has been eliminated. In the few
+	cases where errors may still crop up with database insertions,
+	FeedWordPress will now produce a significantly more manageable and more
+	useful diagnostic message.
+
+*	BUGFIX: NEW POSTS FAILING TO APPEAR IN A CLEANLY-INSTALLED FEEDWORDPRESS
+	SYSTEM. If you encountered a recurring problem with FeedWordPress
+	failing to import new posts, after a clean install of FeedWordPress
+	(i.e., not an upgrade from a previous version), this problem may have
+	been the result of a bug with author-handling which has now been fixed
+	in the 2011.0512 release. (If the problem does *not* go away with the
+	upgrade, this version also includes significant improvements to the
+	Diagnostics system, which will help track down what *is* causing it
+	in your particular case.)
+
+*	PERFORMANCE: New handling of update hashes allows FeedWordPress to avoid
+	a certain kind of infinite loop, caused when two more more different
+	syndicated feeds each carried a version of the same item (for example,
+	because it appeared on two different aggregator feeds that you're
+	syndicating). In previous versions, when this kind of loop cropped up,
+	syndicated posts could pile up an indefinitely large number of revisions
+	-- each revision alternating between the version from each of the two
+	feeds where it appeared -- which would, over time, dramatically inflate
+	the size of the database, and kill the performance of queries on the
+	post table. This issue has been resolved: revisions of the post that
+	have been syndicated once will not be re-syndicated over and over again.
+
+*	AUTHOR LISTS: Lists of authors presented on the Author settings pages
+	should now be easier to scan through, with author names arranged in
+	alphabetical order.
+	
+*	FEED ITEM DATE PARSING: More tweaks to make date-time handling more
+	resilient when feeds provide broken or weird values for the timestamps
+	on syndicated items. FWP will now attempt to work around unparseable
+	timezone values.
+
+*	AUTHOR MATCHING: Now attempts to match author names against the WP login
+	name in addition to display_name; when creating user record, also fills
+	in some best-guess values for nickname, firstname and lastname. Also
+	properly picks up Atom 1.0 author/uri data from feed.
+	
+*	COMPATIBILITY: FeedWordPress has been successfully tested for
+	compatibility with recent releases of WordPress, up to version 3.1.2.
+	
+= 2011.0211 =
+
+*	BUGFIX: DUPLICATE POSTS WHEN GUIDS ARE TOO LONG: When feeds included
+	exceptionally long GUIDs, FeedWordPress could occasionally get into
+	a situation where posts with the long GUIDs would be duplicated over
+	and over again with each update (because FWP failed to store the full
+	GUID, due to length constraints in the relevant database tables).
+	Without the full GUID, FWP would not know that the post had already
+	been syndicated once. This bug has been fixed, and should no longer
+	produce duplicate posts.
+
+*	HTTP TIMEOUT SETTING: If you are frequently running into timeout
+	problems with one or more of the feeds you syndicate, FWP now allows you
+	to adjust the timeout for HTTP requests using a global or feed-by-feed
+	setting.
+
+*	HTTP GET PARAMETERS: You can now temporarily or permanently add HTTP
+	GET parameters to a subscription using an interface in Syndication -->
+	Feeds & Updates. This is especially helpful for making quick, short-term
+	changes to a subscription (for example, to pull in all the previous
+	items from a web service, before settling down to pulling in only newly
+	updated items).
+	
+*	DIAGNOSTICS SYSTEM: Added several new diagnostics which are useful in
+	troubleshooting, and established a framework for add-on modules to hook
+	in with their own diagnostic messages.
+
+*	UI: Adjusted some internal coding, which should allow for settings
+	pages and add-ons to properly display multiple category pickers on a
+	single settings page.
+	
+*	PHP4 COMPATIBILITY TWEAKS: This version makes some tweaks to the handling
+	of object references which should improve compatibility with older
+	versions of PHP. (Although, I should note, web hosts that still force
+	you to run under PHP 4 -- in 2011! -- are *bad web hosts*.)
+
+*	IMPROVED PERFORMANCE: This version eliminates a *major* performance drag
+	that shows up on sites with large numbers of users (due to some poor 
+	decisions about where to place a user query, which caused the user table
+	to be scanned frequently when it did not need to be). If you experienced
+	serious problems with CPU load or slow database performance under
+	2010.0905, which kicked in immediately when FWP was loaded and tended
+	to disappear immediately if FWP was de-activated, it is likely that
+	upgrading away from 2010.0905 to the most recent version will resolve
+	your problem.
+
+
 = 2010.0905 =
 
 *	BUGFIX: CATEGORIES AND TAGS CORRECTLY ASSIGNED IN AUTOMATIC UPDATES.
diff --git a/wp-content/plugins/feedwordpress/syndicatedlink.class.php b/wp-content/plugins/feedwordpress/syndicatedlink.class.php
index c1a45732e337ae27f95c277b2f745e9629b765f4..735bd6e09a9cfefe176445c766b44c470eb29d83 100644
--- a/wp-content/plugins/feedwordpress/syndicatedlink.class.php
+++ b/wp-content/plugins/feedwordpress/syndicatedlink.class.php
@@ -165,16 +165,23 @@ class SyndicatedLink {
 	} /* SyndicatedLink::found () */
 
 	function stale () {
+		global $feedwordpress;
+		
 		$stale = true;
-		if (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='ping')) :
+		if ($this->setting('update/hold')=='ping') :
 			$stale = false; // don't update on any timed updates; pings only
-		elseif (isset($this->settings['update/hold']) and ($this->settings['update/hold']=='next')) :
+		elseif ($this->setting('update/hold')=='next') :
 			$stale = true; // update on the next timed update
-		elseif (!isset($this->settings['update/ttl']) or !isset($this->settings['update/last'])) :
+		elseif ( !$this->setting('update/last') ) :
 			$stale = true; // initial update
+		elseif ($feedwordpress->force_update_all()) :
+			$stale = true; // forced general updating
 		else :
-			$after = ((int) $this->settings['update/last'])
-				+((int) $this->settings['update/ttl'] * 60);
+			$after = (
+				(int) $this->setting('update/last')
+				+ (int) $this->setting('update/fudge')
+				+ ((int) $this->setting('update/ttl') * 60)
+			);
 			$stale = (time() >= $after);
 		endif;
 		return $stale;
@@ -278,17 +285,23 @@ class SyndicatedLink {
 	
 			$this->settings = array_merge($this->settings, $this->flatten_array($channel));
 
-			$this->settings['update/last'] = time(); $ttl = $this->ttl();
+			$this->settings['update/last'] = time();
+			list($ttl, $xml) = $this->ttl(/*return element=*/ true);
+			
 			if (!is_null($ttl)) :
 				$this->settings['update/ttl'] = $ttl;
+				$this->settings['update/xml'] = $xml;
 				$this->settings['update/timed'] = 'feed';
 			else :
-				$this->settings['update/ttl'] = $this->automatic_ttl();
+				$ttl = $this->automatic_ttl();
+				$this->settings['update/ttl'] = $ttl;
+				$this->settings['update/xml'] = NULL;
 				$this->settings['update/timed'] = 'automatically';
 			endif;
-			$this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->settings['update/ttl'], $this);
+			$this->settings['update/fudge'] = rand(0, ($ttl/3))*60;
+			$this->settings['update/ttl'] = apply_filters('syndicated_feed_ttl', $this->setting('update/ttl'), $this);
 
-			if (!isset($this->settings['update/hold']) or $this->settings['update/hold']!='ping') :
+			if (!$this->setting('update/hold') != 'ping') :
 				$this->settings['update/hold'] = 'scheduled';
 			endif;
 
@@ -666,7 +679,7 @@ class SyndicatedLink {
 		return $ret;
 	}
 
-	function ttl () {
+	function ttl ($return_element = false) {
 		if (is_object($this->magpie)) :
 			$channel = $this->magpie->channel;
 		else :
@@ -678,6 +691,7 @@ class SyndicatedLink {
 			// minutes that indicates how long a channel can be
 			// cached before refreshing from the source."
 			// <http://blogs.law.harvard.edu/tech/rss#ltttlgtSubelementOfLtchannelgt>	
+			$xml = 'rss:ttl';
 			$ret = $channel['ttl'];
 		elseif (isset($channel['sy']['updatefrequency']) or isset($channel['sy']['updateperiod'])) :
 			$period_minutes = array (
@@ -705,11 +719,21 @@ class SyndicatedLink {
 			else : $freq = 1;
 			endif;
 			
+			$xml = 'sy:updateFrequency';
 			$ret = (int) ($period_minutes[$period] / $freq);
 		else :
+			$xml = NULL;
 			$ret = NULL;
 		endif;
-		return $ret;
+		
+		if ('yes'==$this->setting('update/minimum', 'update_minimum', 'no')) :
+			$min = (int) $this->setting('update/window', 'update_window', DEFAULT_UPDATE_PERIOD);
+			
+			if ($min > $ret) :
+				$ret = NULL;
+			endif;
+		endif;
+		return ($return_element ? array($ret, $xml) : $ret);
 	} /* SyndicatedLink::ttl() */
 
 	function automatic_ttl () {
@@ -719,7 +743,9 @@ class SyndicatedLink {
 			$updateWindow = DEFAULT_UPDATE_PERIOD;
 		endif;
 
-		$fudgedInterval = $updateWindow+rand(0, 2*($updateWindow/3));
+		// We get a fudge of 1/3 of window from elsewhere. We'll do some more
+		// fudging here.
+		$fudgedInterval = $updateWindow+rand(-($updateWindow/6), 5*($updateWindow/12));
 		return apply_filters('syndicated_feed_automatic_ttl', $fudgedInterval, $this);
 	} /* SyndicatedLink::automatic_ttl () */
 
diff --git a/wp-content/plugins/feedwordpress/syndicatedpost.class.php b/wp-content/plugins/feedwordpress/syndicatedpost.class.php
index df96b783ca948564f1decb0beaae01fd790313e2..e96869e572e8a5602a6c88a7c47a6e6a36451cb2 100644
--- a/wp-content/plugins/feedwordpress/syndicatedpost.class.php
+++ b/wp-content/plugins/feedwordpress/syndicatedpost.class.php
@@ -10,7 +10,7 @@ require_once(dirname(__FILE__).'/feedtime.class.php');
  * different feed formats, which may be useful to FeedWordPress users
  * who make use of feed data in PHP add-ons and filters.
  *
- * @version 2010.0905
+ * @version 2011.0601
  */
 class SyndicatedPost {
 	var $item = null;	// MagpieRSS representation
@@ -618,7 +618,7 @@ class SyndicatedPost {
 		
 		// Ignore whitespace, case, and tag cruft.
 		$theExcerpt = preg_replace('/\s+/', '', strtolower(strip_tags($excerpt)));
-		$theContent = preg_replace('/\s+/', '', strtolower(strip_Tags($content)));
+		$theContent = preg_replace('/\s+/', '', strtolower(strip_tags($content)));
 
 		if ( empty($excerpt) or $theExcerpt == $theContent ) :
 			# If content is available, generate an excerpt.
@@ -755,17 +755,49 @@ class SyndicatedPost {
 		return $ts;
 	} /* SyndicatedPost::updated() */
 
+	var $_hashes = array();
+	function stored_hashes ($id = NULL) {
+		if (is_null($id)) :
+			$id = $this->wp_id();
+		endif;
+
+		if (!isset($this->_hashes[$id])) :
+			$this->_hashes[$id] = get_post_custom_values(
+				'syndication_item_hash', $id
+			);
+			if (is_null($this->_hashes[$id])) :
+				$this->_hashes[$id] = array();
+			endif;
+		endif;
+		return $this->_hashes[$id];
+	}
+
 	function update_hash () {
 		return md5(serialize($this->item));
 	} /* SyndicatedPost::update_hash() */
 
+	/*static*/ function normalize_guid_prefix () {
+		return trailingslashit(get_bloginfo('url')).'?guid=';
+	}
+	
+	/*static*/ function normalize_guid ($guid) {
+		$guid = trim($guid);
+		if (preg_match('/^[0-9a-z]{32}$/i', $guid)) : // MD5
+			$guid = SyndicatedPost::normalize_guid_prefix().strtolower($guid);
+		elseif ((strlen(esc_url($guid)) == 0) or (esc_url($guid) != $guid)) :
+			$guid = SyndicatedPost::normalize_guid_prefix().md5($guid);
+		endif;
+		$guid = trim($guid);
+		return $guid;
+	} /* SyndicatedPost::normalize_guid() */
+	
 	function guid () {
 		$guid = null;
-		if (isset($this->item['id'])): 			// Atom 0.3 / 1.0
+		if (isset($this->item['id'])):						// Atom 0.3 / 1.0
 			$guid = $this->item['id'];
 		elseif (isset($this->item['atom']['id'])) :		// Namespaced Atom
 			$guid = $this->item['atom']['id'];
-		elseif (isset($this->item['guid'])) :			// RSS 2.0
+		elseif (isset($this->item['guid'])) :				// RSS 2.0
 			$guid = $this->item['guid'];
 		elseif (isset($this->item['dc']['identifier'])) :	// yeah, right
 			$guid = $this->item['dc']['identifier'];
@@ -859,8 +891,12 @@ class SyndicatedPost {
 			$author['email'] = $this->feed->channel['author_email'];
 		endif;
 		
-		if (isset($this->item['author_url'])):
+		if (isset($this->item['author_uri'])):
+			$author['uri'] = $this->item['author_uri'];
+		elseif (isset($this->item['author_url'])):
 			$author['uri'] = $this->item['author_url'];
+		elseif (isset($this->feed->channel['author_uri'])) :
+			$author['uri'] = $this->item['author_uri'];
 		elseif (isset($this->feed->channel['author_url'])) :
 			$author['uri'] = $this->item['author_url'];
 		elseif (isset($this->feed->channel['link'])) :
@@ -1199,22 +1235,31 @@ class SyndicatedPost {
 		global $wpdb;
 
 		if ($this->filtered()) : // This should never happen.
-			FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
+			FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__, __FILE__);
 		endif;
 		
-		if (is_null($this->_freshness)) :
+		if (is_null($this->_freshness)) : // Not yet checked and cached.
 			$guid = $wpdb->escape($this->guid());
 
-			$result = $wpdb->get_row("
-			SELECT id, guid, post_modified_gmt
-			FROM $wpdb->posts WHERE guid='$guid'
-			");
-
-			if (!$result) :
+			$q = new WP_Query(array(
+				'fields' => '_synfresh', // id, guid, post_modified_gmt
+				'ignore_sticky_posts' => true,
+				'guid' => $this->guid(),
+			));
+			
+			$old_post = NULL;
+			if ($q->have_posts()) :
+				while ($q->have_posts()) : $q->the_post();
+					$old_post = $q->post;
+				endwhile;
+			endif;
+			
+			if (is_null($old_post)) : // No post with this guid
+				FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is a NEW POST.');
 				$this->_wp_id = NULL;
 				$this->_freshness = 2; // New content
-			else:
-				preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $result->post_modified_gmt, $backref);
+			else :
+				preg_match('/([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)/', $old_post->post_modified_gmt, $backref);
 
 				$last_rev_ts = gmmktime($backref[4], $backref[5], $backref[6], $backref[2], $backref[3], $backref[1]);
 				$updated_ts = $this->updated(/*fallback=*/ true, /*default=*/ NULL);
@@ -1225,12 +1270,13 @@ class SyndicatedPost {
 					and ($updated_ts > $last_rev_ts)
 				);
 				
+				
 				if (!$updated) :
 					// Or the hash...
-					$stored_update_hashes = get_post_custom_values('syndication_item_hash', $result->id);
-					if (count($stored_update_hashes) > 0) :
-						$stored_update_hash = $stored_update_hashes[0];
-						$updated = ($stored_update_hash != $this->update_hash());
+					$hash = $this->update_hash();
+					$seen = $this->stored_hashes($old_post->ID);
+					if (count($seen) > 0) :
+						$updated = !in_array($hash, $seen); // Not seen yet?
 					else :
 						$updated = true; // Can't find syndication meta-data
 					endif;
@@ -1240,18 +1286,27 @@ class SyndicatedPost {
 				if ($updated) : // Ignore if the post is frozen
 					$frozen = ('yes' == $this->link->setting('freeze updates', 'freeze_updates', NULL));
 					if (!$frozen) :
-						$frozen_values = get_post_custom_values('_syndication_freeze_updates', $result->id);
+						$frozen_values = get_post_custom_values('_syndication_freeze_updates', $old_post->ID);
 						$frozen = (count($frozen_values) > 0 and 'yes' == $frozen_values[0]);
 					endif;
 				endif;
 				$updated = ($updated and !$frozen);
 
 				if ($updated) :
+					FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is an update of an existing post.');
 					$this->_freshness = 1; // Updated content
-					$this->_wp_id = $result->id;
+					$this->_wp_id = $old_post->ID;
+					
+					// We want this to keep a running list of all the
+					// processed update hashes.
+					$this->post['meta']['syndication_item_hash'] = array_merge(
+						$this->stored_hashes(),
+						array($this->update_hash())
+					);
 				else :
+					FeedWordPress::diagnostic('feed_items:freshness', 'Item ['.$this->guid().'] "'.$this->entry->get_title().'" is a duplicate of an existing post.');
 					$this->_freshness = 0; // Same old, same old
-					$this->_wp_id = $result->id;
+					$this->_wp_id = $old_post->ID;
 				endif;
 			endif;
 		endif;
@@ -1264,7 +1319,7 @@ class SyndicatedPost {
 
 	function wp_id () {
 		if ($this->filtered()) : // This should never happen.
-			FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
+			FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__, __FILE__);
 		endif;
 		
 		if (is_null($this->_wp_id) and is_null($this->_freshness)) :
@@ -1277,7 +1332,7 @@ class SyndicatedPost {
 		global $wpdb;
 
 		if ($this->filtered()) : // This should never happen.
-			FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__);
+			FeedWordPress::critical_bug('SyndicatedPost', $this, __LINE__, __FILE__);
 		endif;
 		
 		$freshness = $this->freshness();
@@ -1288,6 +1343,7 @@ class SyndicatedPost {
 			);
 
 			if (is_null($this->post['post_author'])) :
+				FeedWordPress::diagnostic('feed_items:rejected', 'Filtered out item ['.$this->guid().'] without syndication: no author available');
 				$this->post = NULL;
 			endif;
 		endif;
@@ -1436,7 +1492,14 @@ class SyndicatedPost {
 			// Kludge to prevent kses filters from stripping the
 			// content of posts when updating without a logged in
 			// user who has `unfiltered_html` capability.
-			add_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
+			$mungers = array('wp_filter_kses', 'wp_filter_post_kses');
+			$removed = array();
+			foreach ($mungers as $munger) :
+				if (has_filter('content_save_pre', $munger)) :
+					remove_filter('content_save_pre', $munger);
+					$removed[] = $munger;
+				endif;
+			endforeach;
 			
 			if ($update and function_exists('get_post_field')) :
 				// Don't munge status fields that the user may
@@ -1445,7 +1508,7 @@ class SyndicatedPost {
 				
 				foreach ($doNotMunge as $field) :
 					$dbpost[$field] = get_post_field($field, $this->wp_id());
-				endforeach;
+				endforeach;				
 			endif;
 			
 			// WP3's wp_insert_post scans current_user_can() for the
@@ -1470,7 +1533,8 @@ class SyndicatedPost {
 				$this->post['ID'] = $this->wp_id();
 				$dbpost['ID'] = $this->post['ID'];
 			endif;
-			$this->_wp_id = wp_insert_post($dbpost);
+			
+			$this->_wp_id = wp_insert_post($dbpost, /*return wp_error=*/ true);
 
 			remove_action(
 			/*hook=*/ 'transition_post_status',
@@ -1488,9 +1552,11 @@ class SyndicatedPost {
 
 			// Turn off ridiculous fucking kludges #1 and #2
 			remove_action('_wp_put_post_revision', array($this, 'fix_revision_meta'));
-			remove_filter('content_save_pre', array($this, 'avoid_kses_munge'), 11);
-	
-			$this->validate_post_id($dbpost, array(__CLASS__, __FUNCTION__));
+			foreach ($removed as $filter) :
+				add_filter('content_save_pre', $removed);
+			endforeach;
+			
+			$this->validate_post_id($dbpost, $update, array(__CLASS__, __FUNCTION__));
 		endif;
 	} /* function SyndicatedPost::insert_post () */
 	
@@ -1511,16 +1577,7 @@ class SyndicatedPost {
 	function normalize_post ($new = true) {
 		global $wpdb;
 
-		$out = array();
-
-		// Why the fuck doesn't wp_insert_post already do this?
-		foreach ($this->post as $key => $value) :
-			if (is_string($value)) :
-				$out[$key] = $wpdb->escape($value);
-			else :
-				$out[$key] = $value;
-			endif;
-		endforeach;
+		$out = $this->post;
 
 		$fullPost = $out['post_title'].$out['post_content'];
 		$fullPost .= (isset($out['post_excerpt']) ? $out['post_excerpt'] : '');
@@ -1541,6 +1598,18 @@ class SyndicatedPost {
 			// FIXME: Option for what to fill a blank title with...
 		endif;
 
+		// Normalize the guid if necessary.
+		$out['guid'] = SyndicatedPost::normalize_guid($out['guid']);
+
+		// Why the fuck doesn't wp_insert_post already do this?
+		foreach ($out as $key => $value) :
+			if (is_string($value)) :
+				$out[$key] = $wpdb->escape($value);
+			else :
+				$out[$key] = $value;
+			endif;
+		endforeach;
+
 		return $out;
 	}
 
@@ -1550,20 +1619,41 @@ class SyndicatedPost {
 	 * @param array $dbpost An array representing the post we attempted to insert or update
 	 * @param mixed $ns A string or array representing the namespace (class, method) whence this method was called.
 	 */
-	function validate_post_id ($dbpost, $ns) {
+	function validate_post_id ($dbpost, $is_update, $ns) {
 		if (is_array($ns)) : $ns = implode('::', $ns);
 		else : $ns = (string) $ns; endif;
-		
+
 		// This should never happen.
 		if (!is_numeric($this->_wp_id) or ($this->_wp_id == 0)) :
-			FeedWordPress::critical_bug(
-				/*name=*/ $ns.'::_wp_id',
+			$verb = ($is_update ? 'update existing' : 'insert new');
+			$guid = $this->guid();
+			$url = $this->permalink();
+			$feed = $this->link->uri(array('add_params' => true));
+
+			// wp_insert_post failed. Diagnostics, or barf up a critical bug
+			// notice if we are in debug mode.
+			$mesg = "Failed to $verb item [$guid]. WordPress API returned no valid post ID.\n"
+				."\t\tID = ".serialize($this->_wp_id)."\n"
+				."\t\tURL = ".FeedWordPress::val($url)
+				."\t\tFeed = ".FeedWordPress::val($feed); 
+			FeedWordPress::diagnostic('updated_feeds:errors', "WordPress API error: $mesg");
+			FeedWordPress::diagnostic('feed_items:rejected', $mesg);
+
+			$mesg = <<<EOM
+The WordPress API returned an invalid post ID
+			   when FeedWordPress tried to $verb item $guid
+			   [URL: $url]
+			   from the feed at $feed 
+
+$ns::_wp_id 
+EOM;
+			FeedWordPress::noncritical_bug(
+				/*message=*/ $mesg,
 				/*var =*/ array(
 					"\$this->_wp_id" => $this->_wp_id,
 					"\$dbpost" => $dbpost,
-					"\$this" => $this
 				),
-				/*line # =*/ __LINE__
+				/*line # =*/ __LINE__, /*filename=*/ __FILE__
 			);
 		endif;
 	} /* SyndicatedPost::validate_post_id() */
@@ -1597,31 +1687,6 @@ class SyndicatedPost {
 		WHERE post_type = 'revision' AND ID='$revision_id'
 		");
 	} /* SyndicatedPost::fix_revision_meta () */
-
-	/**
-	 * SyndicatedPost::avoid_kses_munge() -- If FeedWordPress is processing
-	 * an automatic update, that generally means that wp_insert_post() is
-	 * being called under the user credentials of whoever is viewing the
-	 * blog at the time -- usually meaning no user at all. But if WordPress
-	 * gets a wp_insert_post() when current_user_can('unfiltered_html') is
-	 * false, it will run the content of the post through a kses function
-	 * that strips out lots of HTML tags -- notably <object> and some others.
-	 * This causes problems for syndicating (for example) feeds that contain
-	 * YouTube videos. It also produces an unexpected asymmetry between
-	 * automatically-initiated updates and updates initiated manually from
-	 * the WordPress Dashboard (which are usually initiated under the
-	 * credentials of a logged-in admin, and so don't get run through the
-	 * kses function). So, to avoid the whole mess, what we do here is
-	 * just forcibly disable the kses munging for a single syndicated post,
-	 * by restoring the contents of the `post_content` field.
-	 *
-	 * @param string $content The content of the post, after other filters have gotten to it
-	 * @return string The original content of the post, before other filters had a chance to munge it.
-	 */
-	 function avoid_kses_munge ($content) {
-		 global $wpdb;
-		 return $wpdb->escape($this->post['post_content']);
-	 }
 	 
 	/**
 	 * SyndicatedPost::add_terms() -- if FeedWordPress is processing an
@@ -1641,14 +1706,15 @@ class SyndicatedPost {
 	 * @param object $post The database record for the post just inserted.
 	 */
 	function add_terms ($new_status, $old_status, $post) {
-		if ( is_array($this->post) and isset($this->post['tax_input']) and is_array($this->post['tax_input']) ) :
-			foreach ($this->post['tax_input'] as $taxonomy => $terms) :
-				if (is_array($terms)) :
-					$terms = array_filter($terms); // strip out empties
-				endif;
-				
-				wp_set_post_terms($post->ID, $terms, $taxonomy);
-			endforeach;
+		if ($new_status!='inherit') : // Bail if we are creating a revision.
+			if ( is_array($this->post) and isset($this->post['tax_input']) and is_array($this->post['tax_input']) ) :
+				foreach ($this->post['tax_input'] as $taxonomy => $terms) :
+					if (is_array($terms)) :
+						$terms = array_filter($terms); // strip out empties
+					endif;
+					wp_set_post_terms($post->ID, $terms, $taxonomy);
+				endforeach;
+			endif;
 		endif;
 	} /* SyndicatedPost::add_terms () */
 	
@@ -1669,10 +1735,12 @@ class SyndicatedPost {
 	 */
 	function fix_post_modified_ts ($new_status, $old_status, $post) {
 		global $wpdb;
-		$wpdb->update( $wpdb->posts, /*data=*/ array(
-		'post_modified' => $this->post['post_modified'],
-		'post_modified_gmt' => $this->post['post_modified_gmt'],
-		), /*where=*/ array('ID' => $post->ID) );
+		if ($new_status!='inherit') : // Bail if we are creating a revision.
+			$wpdb->update( $wpdb->posts, /*data=*/ array(
+			'post_modified' => $this->post['post_modified'],
+			'post_modified_gmt' => $this->post['post_modified_gmt'],
+			), /*where=*/ array('ID' => $post->ID) );
+		endif;
 	} /* SyndicatedPost::fix_post_modified_ts () */
 	
 	/**
@@ -1691,38 +1759,40 @@ class SyndicatedPost {
 	 * @param object $post The database record for the post just inserted.
 	 */
 	function add_rss_meta ($new_status, $old_status, $post) {
-		FeedWordPress::diagnostic('syndicated_posts:meta_data', 'Adding post meta-data: {'.implode(", ", array_keys($this->post['meta'])).'}');
-
 		global $wpdb;
-		if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) :
-			$postId = $post->ID;
-			
-			// Aggregated posts should NOT send out pingbacks.
-			// WordPress 2.1-2.2 claim you can tell them not to
-			// using $post_pingback, but they don't listen, so we
-			// make sure here.
-			$result = $wpdb->query("
-			DELETE FROM $wpdb->postmeta
-			WHERE post_id='$postId' AND meta_key='_pingme'
-			");
-
-			foreach ( $this->post['meta'] as $key => $values ) :
-				$eKey = $wpdb->escape($key);
-
-				// If this is an update, clear out the old
-				// values to avoid duplication.
+		if ($new_status!='inherit') : // Bail if we are creating a revision.
+			FeedWordPress::diagnostic('syndicated_posts:meta_data', 'Adding post meta-data: {'.implode(", ", array_keys($this->post['meta'])).'}');
+
+			if ( is_array($this->post) and isset($this->post['meta']) and is_array($this->post['meta']) ) :
+				$postId = $post->ID;
+				
+				// Aggregated posts should NOT send out pingbacks.
+				// WordPress 2.1-2.2 claim you can tell them not to
+				// using $post_pingback, but they don't listen, so we
+				// make sure here.
 				$result = $wpdb->query("
 				DELETE FROM $wpdb->postmeta
-				WHERE post_id='$postId' AND meta_key='$eKey'
+				WHERE post_id='$postId' AND meta_key='_pingme'
 				");
-
-				// Allow for either a single value or an array
-				if (!is_array($values)) $values = array($values);
-				foreach ( $values as $value ) :
-				FeedWordPress::diagnostic('syndicated_posts:meta_data', "Adding post meta-datum to post [$postId]: [$key] = ".FeedWordPress::val($value, /*no newlines=*/ true));
-					add_post_meta($postId, $key, $value, /*unique=*/ false);
+	
+				foreach ( $this->post['meta'] as $key => $values ) :
+					$eKey = $wpdb->escape($key);
+	
+					// If this is an update, clear out the old
+					// values to avoid duplication.
+					$result = $wpdb->query("
+					DELETE FROM $wpdb->postmeta
+					WHERE post_id='$postId' AND meta_key='$eKey'
+					");
+					
+					// Allow for either a single value or an array
+					if (!is_array($values)) $values = array($values);
+					foreach ( $values as $value ) :
+					FeedWordPress::diagnostic('syndicated_posts:meta_data', "Adding post meta-datum to post [$postId]: [$key] = ".FeedWordPress::val($value, /*no newlines=*/ true));
+						add_post_meta($postId, $key, $value, /*unique=*/ false);
+					endforeach;
 				endforeach;
-			endforeach;
+			endif;
 		endif;
 	} /* SyndicatedPost::add_rss_meta () */
 
@@ -1739,11 +1809,17 @@ class SyndicatedPost {
 		global $wpdb;
 
 		$a = $this->named['author'];
-		
+
 		$source = $this->source();
 		$forbidden = apply_filters('feedwordpress_forbidden_author_names',
 			array('admin', 'administrator', 'www', 'root'));
 		
+		// Prepare the list of candidates to try for author name: name from
+		// feed, original source title (if any), immediate source title live
+		// from feed, subscription title, prettied version of feed homepage URL,
+		// prettied version of feed URL, or, failing all, use "unknown author"
+		// as last resort
+
 		$candidates = array();
 		$candidates[] = $a['name'];
 		if (!is_null($source)) : $candidates[] = $source['title']; endif;
@@ -1753,6 +1829,9 @@ class SyndicatedPost {
 		$candidates[] = feedwordpress_display_url($this->link->uri());
 		$candidates[] = 'unknown author';
 		
+		// Pick the first one that works from the list, screening against empty
+		// or forbidden names.
+		
 		$author = NULL;
 		while (is_null($author) and ($candidate = each($candidates))) :
 			if (!is_null($candidate['value'])
@@ -1835,6 +1914,7 @@ class SyndicatedPost {
 			$id = $wpdb->get_var(
 			"SELECT ID FROM $wpdb->users
 			WHERE TRIM(LCASE(display_name)) = TRIM(LCASE('$author'))
+			OR TRIM(LCASE(user_login)) = TRIM(LCASE('$author'))
 			OR (
 				LENGTH(TRIM(LCASE(user_email))) > 0
 				AND TRIM(LCASE(user_email)) = TRIM(LCASE('$test_email'))
@@ -1878,6 +1958,10 @@ class SyndicatedPost {
 					$userdata['user_pass'] = substr(md5(uniqid(microtime())), 0, 6); // just something random to lock it up
 					$userdata['user_email'] = $email;
 					$userdata['user_url'] = $authorUrl;
+					$userdata['nickname'] = $author;
+					$parts = preg_split('/\s+/', trim($author), 2);
+					if (isset($parts[0])) : $userdata['first_name'] = $parts[0]; endif;
+					if (isset($parts[1])) : $userdata['last_name'] = $parts[1]; endif;
 					$userdata['display_name'] = $author;
 					$userdata['role'] = 'contributor';
 					
@@ -1924,7 +2008,7 @@ class SyndicatedPost {
 			endif;
 		endif;
 		return $id;	
-	} // function SyndicatedPost::author_id ()
+	} /* function SyndicatedPost::author_id () */
 
 	/**
 	 * category_ids: look up (and create) category ids from a list of categories
@@ -2007,7 +2091,7 @@ class SyndicatedPost {
 						endif;
 						$term = wp_insert_term($cat_name, $tax);
 						if (is_wp_error($term)) :
-							FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__);
+							FeedWordPress::noncritical_bug('term insertion problem', array('cat_name' => $cat_name, 'term' => $term, 'this' => $this), __LINE__, __FILE__);
 						else :
 							if (!isset($terms[$tax])) :
 								$terms[$tax] = array();
diff --git a/wp-content/plugins/feedwordpress/syndicationdataqueries.class.php b/wp-content/plugins/feedwordpress/syndicationdataqueries.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..90ff6553179a02db09694324663f555c32946d41
--- /dev/null
+++ b/wp-content/plugins/feedwordpress/syndicationdataqueries.class.php
@@ -0,0 +1,100 @@
+<?php
+class SyndicationDataQueries {
+	function SyndicationDataQueries () {
+		add_action('init', array(&$this, 'init'));
+		add_action('parse_query', array(&$this, 'parse_query'), 10, 1);
+		add_filter('posts_search', array(&$this, 'posts_search'), 10, 2);
+		add_filter('posts_where', array(&$this, 'posts_where'), 10, 2);
+		add_filter('posts_fields', array(&$this, 'posts_fields'), 10, 2);
+		add_filter('posts_request', array(&$this, 'posts_request'), 10, 2);
+	}
+
+	function init () {
+		global $wp;
+		$wp->add_query_var('guid');
+	}
+
+	function parse_query (&$q) {
+		if ($q->get('guid')) :
+			$q->is_single = false;		// Causes nasty side-effects.
+			$q->is_singular = true;	// Doesn't?
+		endif;
+		
+		if ($q->get('fields') == '_synfresh') :
+			$q->query_vars['cache_results'] = false; // Not suitable.
+		endif;
+	} /* SyndicationDataQueries::parse_query () */
+	
+	function pre_get_posts (&$q) {
+		// 
+	}
+	
+	function posts_request ($sql, &$query) {
+		if ($query->get('fields') == '_synfresh') :
+			FeedWordPress::diagnostic('feed_items:freshness:sql', "SQL: ".$sql);
+		endif;
+		return $sql;
+	}
+	
+	function posts_search ($search, &$query) {
+		global $wpdb;
+		if ($guid = $query->get('guid')) :
+			if (strlen(trim($guid)) > 0) :
+				$seek = array($guid);
+				
+				// MD5 hashes
+				if (preg_match('/^[0-9a-f]{32}$/i', $guid)) :
+					$seek[] = SyndicatedPost::normalize_guid_prefix().$guid;
+				endif;
+
+				// Invalid URIs, URIs that WordPress just doesn't like, and URIs
+				// that WordPress decides to munge.
+				$nGuid = SyndicatedPost::normalize_guid($guid);
+				if ($guid != $nGuid) :
+					$seek[] = $nGuid;
+				endif;
+				
+				// Escape to prevent frak-ups, injections, etc.
+				$seek = array_map('esc_sql', $seek);
+				
+				// Assemble
+				$guidMatch = "(guid = '".implode("') OR (guid = '", $seek)."')";
+				$search .= " AND ($guidMatch)";
+			endif;
+		endif;
+		
+		if ($query->get('fields')=='_synfresh') :
+			// Ugly hack to ensure we ONLY check by guid in syndicated freshness
+			// checks -- for reasons of both performance and correctness. Pitch:
+			$search .= " -- '";
+		endif;
+		return $search;
+	} /* SyndicationDataQueries::posts_search () */
+	
+	function posts_where ($where, &$q) {
+		// Ugly hack to ensure we ONLY check by guid in syndicated freshness
+		// checks -- for reasons of both performance and correctness. Catch:
+		if (strpos($where, " -- '") !== false) :
+			$bits = explode(" -- '", $where, 2);
+			$where = $bits[0];
+		endif;
+		return $where;
+	} /* SyndicationDataQueries::post_where () */
+	
+	function posts_fields ($fields, &$query) {
+		global $wpdb;
+		if ($f = $query->get('fields')) :
+			switch ($f) :
+			case '_synfresh' :
+				$fields = "{$wpdb->posts}.ID, {$wpdb->posts}.guid, {$wpdb->posts}.post_modified_gmt";
+				break;
+			default :
+				// Do nothing.
+			endswitch;
+		endif;
+		return $fields;
+	} /* SyndicationDataQueries::posts_fields () */
+}
+
+$SDQ = new SyndicationDataQueries;
+