t('Local path')),
array('data' => t('FeedBurner')),
array('data' => t('Verified')),
array('data' => t('Operations'), 'colspan' => '3'),
);
$feeds = _feedburner_get_feeds($cat, array('match' => $keys));
$rows = array();
foreach ($feeds as $feed) {
$row = array();
$row[] = l((isset($feed['alias']) ? $feed['alias'] . ' (' . $feed['path'] . ')' : $feed['path']), $feed['path']);
if (isset($feed['feedburner'])) {
$row[] = l($feed['feedburner'], _feedburner_construct_url($feed['feedburner']));
$row[] = $feed['verified'] ? t('Yes') : t('No');
$row[] = l(t('Edit'), 'admin/build/feedburner/burn/' . $feed['path']);
$row[] = l(t('Unburn'), 'admin/build/feedburner/unburn/' . $feed['path']);
$row[] = l(t('Source'), $feed['path'], array('query' => 'redirect=no'));
}
else {
$row[] = '-';
$row[] = l(t('Burn'), 'admin/build/feedburner/burn/' . $feed['path']);
$row[] = '';
$row[] = '';
$row[] = '';
}
$rows[] = $row;
}
if (empty($rows)) {
$empty_message = $keys ? t('No feeds found.') : t('No feeds available.') ;
$rows[] = array(array('data' => $empty_message, 'colspan' => 5));
}
$output .= theme('table', $header, $rows);
$output .= _feedburner_blurb();
//drupal_add_js('misc/collapse.js');
return $output;
}
/**
* Return a form to filter URL aliases.
*/
function feedburner_build_filter_form(&$form_state, $cat, $keys = '') {
$form['#attributes'] = array('class' => 'search-form');
$form['basic'] = array(
'#type' => 'fieldset',
'#title' => t('Filter feeds'),
);
$form['basic']['inline'] = array(
'#prefix' => '
',
'#suffix' => '
',
);
$form['basic']['inline']['filter'] = array(
'#type' => 'textfield',
'#title' => '',
'#default_value' => $keys,
'#maxlength' => 64,
'#size' => 25,
);
$form['basic']['inline']['submit'] = array(
'#type' => 'submit',
'#value' => t('Filter'),
'#submit' => array('feedburner_build_filter_form_submit_filter'),
);
$form['cat'] = array(
'#type' => 'value',
'#value' => $cat,
);
if (!empty($keys)) {
$form['basic']['inline']['reset'] = array(
'#type' => 'submit',
'#value' => t('Reset'),
'#submit' => array('feedburner_build_filter_form_submit_reset'),
);
}
return $form;
}
/**
* Process filter form submission when the Filter button is pressed.
*/
function feedburner_build_filter_form_submit_filter($form, &$form_state) {
$form_state['redirect'] = 'admin/build/feedburner/list/' . $form_state['values']['cat'] . '/' . trim($form_state['values']['filter']);
}
/**
* Process filter form submission when the Reset button is pressed.
*/
function feedburner_build_filter_form_submit_reset($form, &$form_state) {
$form_state['redirect'] = 'admin/build/feedburner/list/' . $form_state['values']['cat'];
}
function feedburner_burn_form() {
$path = _feedburner_get_path(5);
$feed = db_result(db_query("SELECT feedburner FROM {feedburner} WHERE path = '%s'", $path));
//$feed = _feedburner_load_feed($path);
$form['path'] = array(
'#type' => 'textfield',
'#title' => t('Local Feed'),
'#default_value' => $path,
'#maxlength' => 128,
'#size' => 45,
'#description' => t('Specify the existing feed on your site from which to redirect.'),
'#field_prefix' => url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q='),
'#autocomplete_path' => 'feedburner/autocomplete/all',
);
$form['feedburner'] = array(
'#type' => 'textfield',
'#title' => t('FeedBurner Feed'),
'#default_value' => $feed,
'#maxlength' => 100,
'#size' => 45,
'#description' => t('Requests to the above feed will be requested to this FeedBurner feed. This field is case-sensitive and alphanumeric.'),
'#field_prefix' => _feedburner_construct_url(),
'#autocomplete_path' => 'feedburner/autocomplete/feedburner',
);
//$form['options'] = array(
// '#type' => 'fieldset',
// '#title' => t('Options'),
// '#collapsible' => TRUE,
// '#description' => t('FeedBurner Management API features coming soon.'),
//);
// TODO: Feed Management API Options
$form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
$form['cancel'] = array('#value' => l(t('Cancel'), 'admin/build/feedburner'));
return $form;
}
function feedburner_burn_form_validate($form, &$form_state) {
$path = $form_state['values']['path'];
$feedburner = $form_state['values']['feedburner'];
$path_menu = menu_get_item($path);
if (!valid_url($path) || !$path_menu || !$path_menu['access']) {
form_set_error('path', t("The path '@link_path' is either invalid or you do not have access to it.", array('@link_path' => $path)));
}
if (preg_match('/[^\w-]/', $feedburner)) {
form_set_error('feedburner', 'Invalid FeedBurner feed name');
}
}
function feedburner_burn_form_submit($form, &$form_state) {
_feedburner_save_feed($form_state['values']['path'], $form_state['values']['feedburner']);
drupal_set_message(t('The feed redirection for %path has been saved.', array('%path' => $form_state['values']['path'])));
if (_feedburner_can_api(TRUE)) {
// TODO: AddFeed / ModifyFeed Management API Calls
}
$form_state['redirect'] = 'admin/build/feedburner';
return;
}
function feedburner_unburn_form() {
$path = _feedburner_get_path(5);
$feed = db_result(db_query("SELECT feedburner FROM {feedburner} WHERE path = '%s'", $path));
if (empty($path) || empty($feed)) {
drupal_goto('admin/build/feedburner');
exit();
}
$form['path'] = array(
'#type' => 'hidden',
'#value' => $path,
);
//$form['unburn'] = array(
// '#type' => 'checkbox',
// '#title' => t('Delete the FeedBurner feed %feed from my FeedBurner account.', array('%feed' => $feed->fb_uri)),
// '#default_value' => FALSE,
// '#disabled' => TRUE,
// '#description' => t('FeedBurner Management API features coming soon.'),
//);
//
//if (!_feedburner_can_api(TRUE)) {
// $form['unburn']['#disabled'] = TRUE;
//}
$form['#redirect'] = 'admin/build/feedburner';
return confirm_form($form, t('Are you sure you want to unburn %feed?', array('%feed' => $path)), 'admin/build/feedburner', t('Requests for this feed will no longer be redirected to FeedBurner. But don\'t worry, you can always re-burn this feed to FeedBurner.'));
}
function feedburner_unburn_form_submit($form, &$form_state) {
if ($form_state['values']['confirm']) {
if ($form_state['values']['unburn']) {
// TODO DeleteFeed API implementation for unburn feed submit
}
_feedburner_save_feed($form_state['values']['path']);
drupal_set_message(t('Redirection for %url has been removed.', array('%url' => $form_state['values']['path'])));
$form_state['redirect'] = 'admin/build/feedburner';
return;
}
}
function feedburner_settings_form() {
$form['redirection'] = array(
'#type' => 'fieldset',
'#title' => t('Feed Redirection'),
);
$form['redirection']['feedburner_redirect_status'] = array(
'#type' => 'select',
'#title' => t('Redirection HTTP header status code'),
'#default_value' => variable_get('feedburner_redirect_status', 307),
'#options' => array(
301 => '301 Moved Permanently',
302 => '302 Found',
307 => '307 Temporary Redirect'),
'#description' => t('Please note that the "307 Temporary Redirect" is recommended. For detailed descriptions of HTTP redirect status codes, see the Wikipedia article on HTTP status codes.', array('@link' => 'http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection')),
);
if (module_exists('blog')) {
$form['redirection']['feedburner_blogs'] = array(
'#type' => 'checkbox',
'#title' => t('Allow users to specify a FeedBurner feed for their own blog\'s feed.'),
'#default_value' => variable_get('feedburner_blogs', 0),
'#description' => t('If the user has the permission to blog, this option is found in his/her edit account page. If FeedFlare is enabled for blog content types, this option will also override FeedFlare.', array('@link' => url('user/' . $GLOBALS['user']->uid . '/edit'))),
);
}
$feeds = array(0 => 'None (disabled)');
$result = db_query('SELECT DISTINCT feedburner FROM {feedburner} ORDER BY feedburner');
while ($feed = db_result($result)) {
$feeds[$feed] = $feed;
}
$form['feedflare'] = array(
'#type' => 'fieldset',
'#title' => t('FeedFlare/Standard Stats/Ad Network'),
'#description' => t('See @link for more information.', array('@link' => 'http://www.feedburner.com/fb/a/publishers/feedflare')),
'#collapsible' => FALSE,
);
$form['feedflare']['feedburner_feedflare_feed'] = array(
'#type' => 'select',
'#title' => t('FeedFlare/Standard Stats feed'),
'#default_value' => variable_get('feedburner_feedflare_feed', 0),
'#options' => $feeds,
);
$form['feedflare']['feedburner_feedflare_node_types'] = array(
'#type' => 'checkboxes',
'#title' => t('Display in node types'),
'#default_value' => variable_get('feedburner_feedflare_node_types', array()),
'#options' => node_get_types('names'),
);
$form['feedflare']['feedburner_feedflare_display'] = array(
'#type' => 'checkboxes',
'#title' => t('How to display FeedFlare/Ad Network'),
'#default_value' => variable_get('feedburner_feedflare_display', array('page')),
'#options' => array(
'teaser' => t('Teaser view'),
'page' => t('Full-page view'),
), // TODO: A better way to list node display types?
'#description' => t('When to display the FeedFlare after the node text. There is also a FeedFlare block available.', array('@block' => url('admin/build/block/configure/feedburner/0'))),
);
//$form['feedflare']['feedburner_standardstats'] = array(
// '#type' => 'checkbox',
// '#default_value' => variable_get('feedburner_standardstats', TRUE),
// '#title' => t('Include StandardStats code on pages that don\'t display FeedFlare or Ad Network'),
//);
//$form['account'] = array(
// '#type' => 'fieldset',
// '#title' => t('FeedBurner Account'),
// '#description' => t('To use more advanced features like FeedFlare, e-mail subscriptions, and feed stats, you need to enter your FeedBurner account details. If you do not yet have a FeedBurner account, you can register at @link.', array('@link' => 'https://www.feedburner.com/fb/a/register')),
// '#collapsible' => TRUE,
// '#collapsed' => FALSE,
//);
//$auth = variable_get('feedburner_auth', NULL);
//$form['account']['feedburner_username'] = array(
// '#type' => 'textfield',
// '#title' => t('Your FeedBurner username'),
// '#default_value' => (!empty($auth) ? strtok(base64_decode($auth), ':') : ''),
// '#size' => 25,
// '#maxlength' => 30,
//);
//$form['account']['feedburner_password'] = array(
// '#type' => 'password',
// '#title' => t('Your FeedBurner password'),
// //'#default_value' => '',
// '#size' => 25,
// '#maxlength' => 30,
//);
//$form['account']['verified'] = array(
// '#type' => 'markup',
// '#value' => '' . t('Account status:') . '
' . t('Verified') : 'red">' . t('NOT VERIFIED')) . '
',
//);
//
//if (!_feedburner_can_api()) {
// $form['account']['#title'] .= t(' (DISABLED - requires PHP 5)');
// $form['account']['#collapsed'] = TRUE;
// $form['account']['feedburner_username']['#disabled'] = TRUE;
// $form['account']['feedburner_password']['#disabled'] = TRUE;
//}
$form['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced Settings'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$form['advanced']['feedburner_useragents'] = array(
'#type' => 'textarea',
'#title' => t('User agents allowed direct feed access'),
'#description' => t('Enter one page per line as user agents that will be allowed to access your site\'s feeds without being redirected to FeedBurner. The \'*\' character is a wildcard. User agent strings do not need to be exact (e.g. "feed" will match "feedburner").'),
'#default_value' => preg_replace(array('%^/(.*)/i$%', '/(? 3,
);
$form['advanced']['feedburner_domain'] = array(
'#type' => 'textfield',
'#title' => t('MyBrand custom domain'),
'#description' => t('MyBrand is a premium FeedBurner service that allows you to showcase your feeds by serving them from your own domain (e.g., @domain). You must have access to change your CNAME entry in the DNS records for the domain you wish to change. For more information, see @link.', array('@link' => 'http://www.feedburner.com/fb/a/mybrand', '@domain' => 'feeds.' . $_SERVER['SERVER_NAME'])),
'#default_value' => variable_get('feedburner_domain', 'feeds.feedburner.com'),
'#field_prefix' => 'http://',
'#field_suffix' => '/feedname',
'#size' => 30,
'#maxlength' => 30,
);
$form['array_filter'] = array('#type' => 'value', '#value' => TRUE);
$form['blurb'] = array(
'#type' => 'markup',
'#value' => _feedburner_blurb(),
'#weight' => 10,
);
return system_settings_form($form);
}
function feedburner_settings_form_validate($form, &$form_state) {
$values =& $form_state['values'];
// Fix redirect code to int
$values['feedburner_redirect_status'] = (int) $values['feedburner_redirect_status'];
//// feedburner username && password
//if (!preg_match('/^\w*$/', $values['feedburner_username'])) {
// form_set_error('feedburner_username', 'Invalid FeedBurner username.');
//}
//if (!preg_match('/^\w*$/', $values['feedburner_password'])) {
// form_set_error('feedburner_username', 'Invalid FeedBurner password.');
//}
//else {
// unset($values['feedburner_password']);
//}
// feedburner_useragents
$useragents = preg_replace('/^[|\s]+|[|\s]+$/m', '', $values['feedburner_useragents']);
$useragents = preg_quote($useragents);
if (empty($useragents) || !preg_match('/\w+/', $useragents)) {
drupal_set_message(t('Please enter at least one user agent that will have access to your site\'s feeds. It is strongly recommended to allow both the "feedburner" and "feedvalidator" user agents.'), 'error');
}
$useragents = '/' . preg_replace(array('/[\r\n]+/', '/\\\\\*/'), array('|', '.*'), $useragents) . '/i';
$values['feedburner_useragents'] = $useragents;
// feedburner_domain
$feedburner_domain = $values['feedburner_domain'];
if (!variable_get('drupal_http_request_fails', FALSE) && $feedburner_domain != variable_get('feedburner_domain', 'feeds.feedburner.com') && $feedburner_domain != 'feeds.feedburner.com') {
$request = drupal_http_request('http://' . $feedburner_domain . '/');
unset($request->data);
if (!isset($request->headers['X-FB-Host']) || !isset($request->code) || $request->code != 400 || !isset($request->error) || $request->error != 'You must provide a feed uri') {
// TODO: Insert help link for CNAME MyBrand editing (http://www.feedburner.com/fb/a/publishers/mybrand)
drupal_set_message(t('The MyBrand domain @domain failed verification. Make sure you have edited the domain\'s CNAME settings before enabling this option.', array('@domain' => $feedburner_domain)), 'error');
}
}
}
function _feedburner_save_feed($path, $feedburner = NULL) {
$current = db_result(db_query("SELECT feedburner FROM {feedburner} WHERE path = '%s'", $path));
if (empty($feedburner) && !empty($current)) {
db_query("DELETE FROM {feedburner} WHERE path = '%s'", $path);
}
else {
if (!empty($current) && $current != $feedburner) {
db_query("UPDATE {feedburner} SET feedburner = '%s' WHERE path = '%s'", $feedburner, $path);
_feedburner_verify_feed($path, $feedburner);
}
elseif (empty($current)) {
db_query("INSERT INTO {feedburner} (path, feedburner) VALUES ('%s', '%s')", $path, $feedburner);
_feedburner_verify_feed($path, $feedburner);
}
}
return (db_affected_rows() != 0);
}
// TODO: Split into _get_feeds and _process_feeds?
function _feedburner_get_feeds($cat = 'site', $options = array()) {
$default_options = array('sort' => TRUE, 'alias' => TRUE, 'feedburner' => TRUE, 'match' => FALSE);
$options = array_merge($default_options, $options);
$feeds = array();
// Site feeds (and various module feeds)
if ($cat == 'site' || $cat == 'all') {
$feeds[] = array('path' => 'rss.xml', 'description' => variable_get('site_name', 'Drupal') . ' RSS');
$feeds[] = array('path' => 'aggregator/feed', 'description' => 'Aggregator RSS', 'module' => 'aggregator');
//$feeds[] = array('path' => 'blog/feed', 'description' => 'Blogs', 'module' => 'blog');
$feeds[] = array('path' => 'crss', 'description' => variable_get('site_name', 'Drupal') . ' Comments', 'module' => 'commentrss');
$feeds[] = array('path' => 'atom/feed', 'description' => variable_get('site_name', 'Drupal') . ' Atom', 'module' => 'atom');
}
// TODO: Views integration
//if (preg_match('/all|views/', $cat) && module_exists('views')) {
// $result = db_query("SELECT url, page_title FROM {view_view} WHERE page_type = 'views_rss' OR page_type = 'views_podcast'");
// while ($view_details = db_fetch_object($result)) {
// $feeds[] = array('path' => $view_details->url, 'cat' => 'views', 'description' => $view_details->page_title);
// }
// $result = db_query("SELECT v.url, v.page_title FROM {view_view} v, {view_argument} a WHERE a.type = 'rss_feed' and v.vid = a.vid");
// while ($viewargs_details = db_fetch_object($result)) {
// $feeds[] = array('path' => $viewargs_details->url . '/feed', 'cat' => 'views', 'description' => $viewargs_details->page_title);
// }
// unset($result);
//}
// TODO: Content integration
//$result = db_query('SELECT nid, title FROM {node} WHERE status = 1');
//while ($node_details = db_fetch_object($result)) {
// $feeds[] = array('path' => 'node/' . $node_details->nid . '/feed', 'cat' => 'content', 'description' => $node_details->title);
//}
//unset($result);
// Blog module feeds
if (($cat == 'all' || $cat == 'blogs') && module_exists('blog')) {
$feeds[] = array('path' => 'blog/feed', 'description' => variable_get('site_name', 'Drupal') . ' blogs');
// Get all user blog feeds for users with the blogging permission granted
$blog_roles = user_roles(TRUE, 'create blog entries');
$blog_roles_sql = (count($blog_roles) ? (isset($blog_roles[2]) ? ' OR u.uid > 1' : ' OR ur.rid IN (' . db_placeholders($blog_roles) . ')') : '');
$sql = "SELECT u.uid, u.name FROM {users} u LEFT JOIN {users_roles} ur ON ur.uid = u.uid WHERE u.uid = 1" . $blog_roles_sql;
$result = db_query($sql, array_keys($blog_roles));
while ($user_details = db_fetch_object($result)) {
$feeds[] = array('path' => 'blog/' . $user_details->uid . '/feed', 'description' => $user_details->name . "'s Blog");
}
unset($result);
}
// Taxonomy feeds
if (($cat == 'all' || $cat == 'taxonomy') && module_exists('taxonomy')) {
$result = db_query('SELECT tid, name FROM {term_data}');
while ($term_details = db_fetch_object($result)) {
$feeds[] = array('path' => 'taxonomy/term/' . $term_details->tid . '/0/feed', 'description' => $term_details->name);
}
unset($result);
}
// FeedBurner feeds
// TODO: Fetch FeedBurner feeds from FeedManagement API
$feedburner_feeds = array();
if ($cat == 'feedburner' || $options['feedburner']) {
$query = db_query("SELECT path, feedburner, verified FROM {feedburner}");
while ($feed = db_fetch_array($query)) {
if ($cat == 'all' || $cat == 'feedburner' || $cat == 'site') {
$feeds[] = $feed;
}
else {
$feedburner_feeds[$feed['path']] = $feed;
}
}
}
$keys = array();
$keepers = array();
foreach ($feeds as $feed) {
if (isset($feed['module']) && !module_exists($feed['module'])) {
continue;
}
// Merge information
if (isset($keys[$feed['path']])) {
$index = $keys[$feed['path']];
$keepers[$index] = array_merge($feed, $keepers[$index]);
continue;
}
// Lookup alias
if ($options['alias']) {
$alias = drupal_get_path_alias($feed['path']);
if ($alias != $feed['path']) {
$feed['alias'] = $alias;
}
}
// Match regular expressions
if ($options['match']) {
$regex = '/' . preg_quote($options['match'], '/') . '/i';
$feed['value'] = FALSE;
foreach (array('path', 'alias', 'feedburner') as $field) {
if (isset($feed[$field]) && preg_match($regex, $feed[$field])) {
$value = levenshtein($options['match'], $feed[$field]);
if ($feed['value'] === FALSE || $value < $feed['value']) {
$feed['value'] = $value;
}
}
}
if ($feed['value'] === FALSE) {
continue;
}
}
// Load FeedBurner Data
if ($options['feedburner'] && isset($feedburner_feeds[$feed['path']])) {
$feed = array_merge($feed, $feedburner_feeds[$feed['path']]);
}
$keepers[] = $feed;
$keys[$feed['path']] = count($keepers) - 1;
}
$feeds = $keepers;
// Sort by array key (custom sort)
if ($options['sort']) {
// My funkly little sort function that sorts 'blog' and 'blog1' ahead of 'blog/...' and recurses down each section of the path
function _feedburner_temp_sort_path($a, $b) {
$a = explode('/', $a, 2);
$b = explode('/', $b, 2);
//return (intval($a[0]) xor intval($b[0]) ? intval($a[0]) : ($result = strnatcasecmp($a[0], $b[0]) ? $result : _feedburner_temp_sort_path($a[1], $b[1])));
if (intval($a[0]) xor intval($b[0])) {
return intval($a[0]);
}
elseif ($result = strnatcasecmp($a[0], $b[0])) {
return $result;
}
else {
return _feedburner_temp_sort_path($a[1], $b[1]);
}
}
function _feedburner_temp_sort_fields($a, $b) {
if (isset($a['value']) && isset($b['value']) && $a['value'] != $b['value']) {
return $a['value'] > $b['value'];
}
else {
return _feedburner_temp_sort_path((isset($a['alias']) ? $a['alias'] : $a['path']), (isset($b['alias']) ? $b['alias'] : $b['path']));
}
}
usort($feeds, '_feedburner_temp_sort_fields');
}
return $feeds;
}
// TODO: CLEANUP AND OPTIMIZE!
// TODO: Make this a callback instead of private function
function _feedburner_verify_feed($local, $feedburner) {
if (!variable_get('drupal_http_request_fails', FALSE)) {
for ($i = 0; $i < 3; $i++) {
$url = NULL;
$request = NULL;
$message_start = NULL;
$results = array(NULL, NULL, NULL, time());
switch ($i) {
case 0:
$url = url($local, array('absolute' => TRUE, 'query' => 'redirect=no'));
$message_start = t('Local feed ');
break;
case 1:
$url = _feedburner_construct_url($feedburner);
$message_start = t('FeedBurner feed ');
break;
case 2:
$url = url($local, array('absolute' => TRUE));
$message_start = t('Local feed redirection for ');
break;
}
$request = drupal_http_request($url);
unset($request->data);
switch ($i) {
case 0:
$url = url($local, array('absolute' => TRUE));
case 1:
$results[$i] = (isset($request->code) && $request->code == '200'
&& is_array($request->headers) && preg_match('/rss|atom|xml/', $request->headers['Content-Type']));
break;
case 2:
$results[$i] = (isset($request->code)
&& $request->code == variable_get('feedburner_redirect_status', 307)
&& isset($request->redirect_code) && $request->redirect_code == '200'
&& isset($request->redirect_url) && $request->redirect_url == _feedburner_construct_url($feedburner));
break;
}
//if ($result[$i]) {
// drupal_set_message($message_start . t('@link verified.', array('@link' => $url)));
//}
if (!$results[$i]) {
$results[3] = 0;
drupal_set_message($message_start . t('@link failed verification. @error', array('@link' => $url, '@error' => $request->error)), 'error');
break;
}
}
}
db_query("UPDATE {feedburner} SET verified = %d WHERE path = '%s' AND feedburner = '%s'", $results[3], $local, $feedburner);
}
function feedburner_autocomplete($cat) {
$key = trim(_feedburner_get_path(4));
$feeds = _feedburner_get_feeds($cat, array('match' => $key, 'feedburner' => FALSE));
$keepers = array();
foreach ($feeds as $feed) {
if ($cat == 'feedburner') {
$keepers[$feed['feedburner']] = $feed['feedburner'];
}
else {
$keepers[$feed['path']] = ($feed['alias'] ? $feed['alias'] . ' (' . $feed['path'] . ')' : $feed['path']) . ($feed['description'] ? ' - ' . $feed['description'] : '');
}
if (count($keepers) == 10) {
break;
}
}
print drupal_to_js($keepers);
exit();
}