Index: ad.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ad/ad.module,v
retrieving revision 1.2.2.29.2.83.2.16.2.4
diff -u -r1.2.2.29.2.83.2.16.2.4 ad.module
--- ad.module	3 Mar 2009 11:25:59 -0000	1.2.2.29.2.83.2.16.2.4
+++ ad.module	5 Mar 2009 16:45:17 -0000
@@ -9,6 +9,7 @@
  *   Jeremy Andrews <jeremy@tag1consulting.com>.
  */
 
+require_once('token_ad.inc');
 
 /**
  * Implementation of hook_theme().
@@ -1312,38 +1313,38 @@
       switch ($arg1) {
         case 'expired':
           return array(
-            'subject' => t('[%sitename ad] %event notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" that was being displayed on the %sitename website has expired.\n\n  Your advertisement was viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] %event notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" that was being displayed on the %site-name website has expired.\n\n  Your advertisement was viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
         case '-expired':
           return array(
-            'subject' => t('[%sitename ad] expiration notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" that is being displayed on the %sitename website will expire on %autoexpire_large.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] expiration notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" that is being displayed on the %site-name website will expire on %autoexpire_large.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
         case 'active':
           return array(
-            'subject' => t('[%sitename ad] %event notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" is now actively being displayed on the %sitename website.\n\n  Your advertisement has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] %event notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" is now actively being displayed on the %site-name website.\n\n  Your advertisement has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
         case '-active':
           return array(
-            'subject' => t('[%sitename ad] activation notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" will be actively displayed on the %sitename website on %autoactivate_large.\n\n  You can view statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] activation notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" will be actively displayed on the %site-name website on %autoactivate_large.\n\n  You can view statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
         case 'click':
           return array(
-            'subject' => t('[%sitename ad] %event notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been clicked.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You will receive this %frequency  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] %event notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been clicked.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You will receive this %frequency  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
         case 'approved':
           return array(
-            'subject' => t('[%sitename ad] %event notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been approved.\n\n  You can view statistics about this advertisement at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] %event notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been approved.\n\n  You can view statistics about this advertisement at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
         case 'denied':
           return array(
-            'subject' => t('[%sitename ad] %event notification'),
-            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %sitename website has been denied and will not be displayed.\n\n  You can view statistics about this advertisement at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
+            'subject' => t('[%site-name ad] %event notification'),
+            'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification to inform you that your advertisement \"%title\" on the %site-name website has been denied and will not be displayed.\n\n  You can view statistics about this advertisement at the following url:\n    %url\n\nRegards,\n The %site-name Team\n\n-\n%site-url"),
           );
       }
       break;
Index: notify/ad_notify.info
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ad/notify/Attic/ad_notify.info,v
retrieving revision 1.1.2.1.2.3
diff -u -r1.1.2.1.2.3 ad_notify.info
--- notify/ad_notify.info	9 Feb 2009 20:39:09 -0000	1.1.2.1.2.3
+++ notify/ad_notify.info	5 Mar 2009 09:34:53 -0000
@@ -2,5 +2,6 @@
 name = Notify
 package = Ad
 dependencies[] = ad_owners
+dependencies[] = token
 description = Receive email notifications regarding ads.
 core = 6.x
Index: notify/ad_notify.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ad/notify/Attic/ad_notify.install,v
retrieving revision 1.1.2.2.2.6.2.3
diff -u -r1.1.2.2.2.6.2.3 ad_notify.install
--- notify/ad_notify.install	16 Feb 2009 17:06:49 -0000	1.1.2.2.2.6.2.3
+++ notify/ad_notify.install	1 Mar 2009 17:59:50 -0000
@@ -97,6 +97,12 @@
         'type' => 'text',
         'not null' => FALSE,
       ),
+      'roles' => array(
+        'type' => 'varchar',
+        'length' => '255',
+        'not null' => TRUE,
+        'default' => '',
+      ),
     ),
     'primary key' => array('notid'),
     'unique keys' => array(
@@ -122,6 +128,15 @@
   drupal_install_schema('ad_notify');
 }
 
+function ad_notify_update_6001() {
+  $return = array();
+  db_add_field($return, 'ad_notify', 'roles', array('type' => 'varchar', 'length' => '255', 'not null' => TRUE, 'default' => ''));
+
+  $return[] = update_sql('UPDATE {ad_notify} SET subject = REPLACE(subject, "%sitename", "%site-name")');
+  $return[] = update_sql('UPDATE {ad_notify} SET body = REPLACE(body, "%siteurl", "%site-url")');
+
+  return $return;
+}
 
 /**
  * Allow complete uninstallation of the ad_notify module.
Index: notify/ad_notify.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/ad/notify/Attic/ad_notify.module,v
retrieving revision 1.1.2.2.2.13.2.6.2.1
diff -u -r1.1.2.2.2.13.2.6.2.1 ad_notify.module
--- notify/ad_notify.module	23 Feb 2009 22:39:04 -0000	1.1.2.2.2.13.2.6.2.1
+++ notify/ad_notify.module	5 Mar 2009 09:34:33 -0000
@@ -31,17 +31,23 @@
 function ad_notify_menu() {
   $items = array();
 
-  $items['node/%node/adowners/%user/notifications'] = array(
-    'title callback' => 'owner_notifications_title',
-    'title arguments' => array('!owner' => 3),
+  $items['admin/content/ad/notifications'] = array(
+    'title' => 'Global notifications',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('ad_notify_overview_form', 1, 3),
-    'access callback' => 'ad_permission',
-    'access arguments' => array(1, 'manage owners'),
+    'page arguments' => array('ad_notify_overview_form', '0', '0'),
+    'access arguments' => array('administer advertisements'),
     'type' => MENU_LOCAL_TASK,
-    'weight' => 4,
+    'weight' => 6,
+  );
+  $items['admin/content/ad/notifications/%ad_notification/delete'] = array(
+    'title' => 'Delete notification',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('ad_notify_confirm_delete', '0', '0', 4),
+    'access arguments' => array('administer advertisements'),
+    'weight' => 2,
   );
-  $items['node/%node/notifications'] = array(
+
+  $items['node/%/notifications'] = array(
     'title' => 'My notifications',
     'page callback' => 'drupal_get_form',
     'page arguments' => array('ad_notify_overview_form', 1),
@@ -50,10 +56,20 @@
     'type' => MENU_LOCAL_TASK,
     'weight' => 4,
   );
-  $items['node/%node/adowners/%user/notifications/%ad_notification/delete'] = array(
+  $items['node/%/adowners/%/notifications'] = array(
+    'title callback' => 'owner_notifications_title',
+    'title arguments' => array('!owner' => 3),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('ad_notify_overview_form', 1, 3),
+    'access callback' => 'ad_permission',
+    'access arguments' => array(1, 'manage owners'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 4,
+  );
+  $items['node/%/adowners/%/notifications/%ad_notification/delete'] = array(
     'title' => 'Delete notification',
-    'page callback' => 'ad_notify_confirm_delete_page',
-    'page arguments' => array(1, 3, 5),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('ad_notify_confirm_delete', 1, 3, 5),
     'access callback' => 'ad_permission',
     'access arguments' => array(1, array('manage owners', 'manage own notifications')),
     'type' => MENU_CALLBACK,
@@ -71,13 +87,12 @@
 
 /**
  * Implementation of hook_cron().
- * For performance reasons, all notifications are actually sent via this cron 
- * hook.
+ * Send time based notifications and those, who has negative delay.
  */
 function ad_notify_cron() {
   // Walk through all configured notifications and determine if any need to be
   // emailed. 
-  $result = db_query('SELECT n.notid, o.aid, n.oid, n.event, n.queued, n.delay, n.sent, n.expire, n.address, n.subject, n.body FROM {ad_notify} n INNER JOIN {ad_owners} o ON n.oid = o.oid WHERE n.status = %d', AD_NOTIFY_ENABLED);
+  $result = db_query('SELECT n.notid, o.aid, n.oid, n.event, n.queued, n.delay, n.sent, n.expire, n.address, n.subject, n.body, n.roles FROM {ad_notify} n INNER JOIN {ad_owners} o ON n.oid = o.oid WHERE n.status = %d', AD_NOTIFY_ENABLED);
   while ($notification = db_fetch_object($result)) {
     $send = FALSE;
     // Handle special case 'regular' notification that is simply a time-based
@@ -136,75 +151,42 @@
  * Send email notifications using PHP mail() function.
  */
 function ad_notify_send_mail($notification, $count = 0) {
-  $uid = db_result(db_query('SELECT uid FROM {ad_owners} WHERE oid = %d', $notification->oid));
-  $node = node_load(array('nid' => $notification->aid));
-  $owner = user_load(array('uid' => $uid));
-  $statistics = ad_statistics($notification->aid);
-  $notifications = module_invoke_all('adnotifyapi', 'register');
-  $variables = array(
-    '%owner_name' => $owner->name,
-    '%owner_mail' => $owner->mail,
-    '%owner_uid' => $owner->uid,
-    '%sitename' => variable_get('site_name', 'drupal'),
-    '%status' => $node->adstatus,
-    '%type' => $node->adtype,
-    '%event' => $notification->event,
-    '%frequency' => t(strtolower($notifications[$notification->event]), array('@when' => format_interval($notification->delay))),
-    '%redirect' => url($node->redirect, array('absolute' => TRUE)),
-    '%aid' => $notification->aid,
-    '%title' => $node->title,
-    '%url' => url("node/$node->nid", array('absolute' => TRUE)),
-    '%siteurl' => url('', array('absolute' => TRUE)),
-    '%comments' => $node->comment_count,
-    '%count' => $count,
-    '%created_small' => format_date($node->created, 'small'),
-    '%created_medium' => format_date($node->created, 'medium'),
-    '%created_large' => format_date($node->created, 'large'),
-    '%activated_small' => $node->activated ? format_date($node->activated, 'small') : t('never'),
-    '%activated_medium' => $node->activated ? format_date($node->activated, 'medium') : t('never'),
-    '%activated_large' => $node->activated ? format_date($node->activated, 'large') : t('never'),
-    '%expired_small' => $node->expired ? format_date($node->expired, 'small') : t('never'),
-    '%expired_medium' => $node->expired ? format_date($node->expired, 'medium') : t('never'),
-    '%expired_large' => $node->expired ? format_date($node->expired, 'large') : t('never'),
-    '%autoactivate_small' => $node->autoactivate ? format_date($node->autoactivate, 'small') : t('never'),
-    '%autoactivate_medium' => $node->autoactivate ? format_date($node->autoactivate, 'medium') : t('never'),
-    '%autoactivate_large' => $node->autoactivate ? format_date($node->autoactivate, 'large') : t('never'),
-    '%autoexpire_small' => $node->autoexpire ? format_date($node->autoexpire, 'small') : t('never'),
-    '%autoexpire_medium' => $node->autoexpire ? format_date($node->autoexpire, 'medium') : t('never'),
-    '%autoexpire_large' => $node->autoexpire ? format_date($node->autoexpire, 'large') : t('never'),
-    '%maxviews' => $node->maxviews,
-    '%maxclicks' => $node->maxclicks,
-    '%global_views' => $statistics['global']['views'],
-    '%global_clicks' => $statistics['global']['clicks'],
-    '%last_year_views' => $statistics['last_year']['views'],
-    '%last_year_clicks' => $statistics['last_year']['clicks'],
-    '%this_year_views' => $statistics['this_year']['views'],
-    '%this_year_clicks' => $statistics['this_year']['clicks'],
-    '%last_month_views' => $statistics['last_month']['views'],
-    '%last_month_clicks' => $statistics['last_month']['clicks'],
-    '%this_month_views' => $statistics['this_month']['views'],
-    '%this_month_clicks' => $statistics['this_month']['clicks'],
-    '%this_week_views' => $statistics['this_week']['views'],
-    '%this_week_clicks' => $statistics['this_week']['clicks'],
-    '%yesterday_views' => $statistics['yesterday']['views'],
-    '%yesterday_clicks' => $statistics['yesterday']['clicks'],
-    '%today_views' => $statistics['today']['views'],
-    '%today_clicks' => $statistics['today']['clicks'],
-    '%last_hour_views' => $statistics['last_hour']['views'],
-    '%last_hour_clicks' => $statistics['last_hour']['clicks'],
-    '%this_hour_views' => $statistics['this_hour']['views'],
-    '%this_hour_clicks' => $statistics['this_hour']['clicks'],
-  );
-  // TODO: Add hook to allow other modules to define variables.
-
-  // TODO: Should the from_address be configurable?
-  drupal_mail(
-    'ad_notify_mail',                                   // mail key
-    $notification->address,                             // to address
-    strtr($notification->subject, $variables),          // subject
-    wordwrap(strtr($notification->body, $variables), 72),      // message
-    variable_get('site_mail', ini_get('sendmail_from')) // from address
-  );
+  $owner = user_load($notification->uid);
+
+  $send = TRUE;
+  // Send notification only for user who has a permission
+  if ($notification->roles) {
+    $send = FALSE;
+    $notification->roles = unserialize($notification->roles);
+    foreach ($notification->roles as $rid) {
+      if (isset($owner->roles[$rid])) {
+        $send = TRUE;
+        break;
+      }
+    }
+  }
+
+  if ($send) {
+    $node = node_load($notification->aid);
+    $node->notification = $notification;
+
+    $replacements = array(
+      'global' => NULL,
+      'ad' => $node,
+      'ad_owner' => $owner,
+    );
+    $notification->body = token_replace_multiple($notification->body, $replacements, '%', '');
+    $notification->subject = token_replace_multiple($notification->subject, $replacements, '%', '');
+
+    // TODO: Should the from_address be configurable?
+    drupal_mail(
+      'ad_notify_mail',                                                   // mail key
+      $notification->address ? $notification->address : $owner->mail,     // to address
+      $notification->subject,                                             // subject
+      wordwrap($notification->body, 72),                                  // message
+      variable_get('site_mail', ini_get('sendmail_from'))                 // from address
+    );
+  }
 }
 
 /**
@@ -236,47 +218,93 @@
 }
 
 /**
+ * Implementation of hook_adowners().
+ */
+function ad_notify_adowners($op, $arg1 = NULL, $arg2 = NULL) {
+  switch ($op) {
+    case 'overview':
+      return l(t('notifications'), 'node/'. $arg1 .'/adowners/'. $arg2 .'/notifications');
+
+    case 'add':
+      if ($arg2['aid'] && $arg2['oid']) {
+        $owner = user_load($arg2['uid']);
+
+        $result = db_query('SELECT * FROM {ad_notify} WHERE aid = 0 AND oid = 0');
+        while ($template = db_fetch_object($result)) {
+          db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s')", $arg2['aid'], $arg2['oid'], $template->event, $template->delay, $template->expire, $template->locked, AD_NOTIFY_ENABLED, $owner->mail, $template->subject, $template->body);
+        }
+      }
+      break;
+
+    case 'remove':
+      if ($arg1) {
+        $result = db_query('DELETE FROM {ad_notify} WHERE oid = %d', $arg1);
+      }
+      break;
+  }
+}
+
+/**
  * Notification overview form.
  */
-function ad_notify_overview_form($form_state, $node, $owner = NULL, $notid = 0) {
+function ad_notify_overview_form($form_state, $nid = 0, $uid = NULL, $notid = 0) {
   global $user;
-  if (arg(2) == 'notifications') {
-    drupal_set_title('My notifications');
-  }
-  else {
-    drupal_set_title('Notifications');
-  }
-  if (!isset($owner)) {
+  if (is_null($uid)) {
+    $uid = $user->uid;
     $owner = $user;
   }
+  if ($uid && !$owner) {
+    $owner = user_load($uid);
+  }
+
+  $oid = (int)db_result(db_query('SELECT oid FROM {ad_owners} WHERE aid = %d AND uid = %d', $nid, $uid));
+  $notifications = module_invoke_all('adnotifyapi', 'register');
 
-  $oid = db_result(db_query('SELECT oid FROM {ad_owners} WHERE aid = %d AND uid = %d', $node->nid, $owner->uid));
-  if (isset($oid)) {
-    $notifications = module_invoke_all('adnotifyapi', 'register');
-
-    $header = array(
-      array('data' => t('Last sent'), 'field' => 'sent', 'sort' => 'desc'),
-      array('data' => t('Notification'), 'field' => 'event'),
-      array('data' => t('Status'), 'field' => 'status'),
-      array('data' => t('Action'))
-    );
-
-    $sql = "SELECT notid, event, delay, sent, address, status FROM {ad_notify} WHERE oid = %d";
-    $sql .= tablesort_sql($header);
-    $result = pager_query($sql, 25, 0, NULL, $oid);
+  $header = array(
+    array('data' => t('Last sent'), 'field' => 'sent', 'sort' => 'desc'),
+    array('data' => t('Notification'), 'field' => 'event'),
+    array('data' => t('Status'), 'field' => 'status'),
+    array('data' => t('Action'))
+  );
+
+  $sql = "SELECT notid, event, delay, sent, address, status, roles FROM {ad_notify} WHERE oid = %d";
+  $sql .= tablesort_sql($header, 'oid DESC, ');
+  $result = pager_query($sql, 25, 0, NULL, $oid);
+
+  $rows = array();
+  while ($notify = db_fetch_object($result)) {
+    $list_notification = TRUE;
+    // Check if user has permission to see the notification.
+    if ($uid && $notify->roles) {
+      $list_notification = FALSE;
+      $notify->roles = unserialize($notify->roles);
+      foreach ($notify->roles as $rid) {
+        if (isset($owner->roles[$rid])) {
+          $list_notification = TRUE;
+          break;
+        }
+      }
+    }
 
-    $rows = array();
-    while ($notify = db_fetch_object($result)) {
+    if (!$uid || $list_notification) {
       $row = array();
       $row[] = $notify->sent ? t('!time ago', array('!time' => format_interval(time() - $notify->sent))) : t('Never');
       $row[] = t($notifications[$notify->event], array('@when' => format_interval($notify->delay)));
       $row[] = $notify->status == AD_NOTIFY_ENABLED ? t('enabled') : t('disabled');
-      $row[] = l(t('edit'), 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications/' .$notify->notid. '/edit') .' '. l(t('delete'), 'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications/'. $notify->notid .'/delete');
+      if ($oid) {
+        $row[] = l(t('edit'), 'node/'. $nid .'/adowners/'. $uid .'/notifications/' .$notify->notid. '/edit') .' '. l(t('delete'), 'node/'. $nid .'/adowners/'. $uid .'/notifications/'. $notify->notid .'/delete');
+      }
+      else if (user_access('administer advertisements')) {
+        $row[] = l(t('edit'), 'admin/content/ad/notifications/' .$notify->notid. '/edit') .' '. l(t('delete'), 'admin/content/ad/notifications/'. $notify->notid .'/delete');
+      }
+      else {
+        $row[] = 'N/A';
+      }
       $rows[] = $row;
     }
-    $output = theme('table', $header, $rows);
-    $output .= theme('pager', NULL, 25, 0);
   }
+  $output = theme('table', $header, $rows);
+  $output .= theme('pager', NULL, 25, 0);
 
   $form = array();
 
@@ -317,7 +345,7 @@
     '#default_value' => $notid ? $notification->expire : 0,
   );
 
-  if (ad_permission($node->nid, 'manage owners') && arg(2) == 'adowners' && 
+  if (ad_permission($nid, 'manage owners') && arg(2) == 'adowners' && 
       $user->uid != arg(3)) {
     $form['create']['locked'] = array(
       '#type' => 'checkbox',
@@ -342,20 +370,31 @@
     );
   }
 
-  // TODO: Make it possible for admins to modify email address, and even to
-  // enter multiple email addresses.  Wrap this in a special permission, as 
-  // it involves trust to configure notifications to unverified addresses.
-  $form['create']['mail']['address-display'] = array(
-    '#type' => 'markup',
-    '#value' => '<b>'. t('Notify address') .':</b><br />'. t('The email will be sent to %address.', array('%address' => $owner->mail)),
-    '#prefix' => '<div class="container-inline">',
-    '#suffix' => '</div>',
-  );
+  if ($uid) {
+    // TODO: Make it possible for admins to modify email address, and even to
+    // enter multiple email addresses.  Wrap this in a special permission, as 
+    // it involves trust to configure notifications to unverified addresses.
+    $form['create']['mail']['address-display'] = array(
+      '#type' => 'markup',
+      '#value' => '<b>'. t('Notify address') .':</b><br />'. t('The email will be sent to %address.', array('%address' => $owner->mail)),
+      '#prefix' => '<div class="container-inline">',
+      '#suffix' => '</div>',
+    );
 
-  $form['create']['mail']['address'] = array(
-    '#type' => 'hidden',
-    '#value' => $owner->mail,
-  );
+    $form['create']['mail']['address'] = array(
+      '#type' => 'hidden',
+      '#value' => $owner->mail,
+    );
+  }
+  else {
+    $roles = user_roles(TRUE);
+    $form['create']['roles'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Notify roles'),
+      '#description' => t('Only listed roles will get this notification. Live blank to send always.'),
+      '#options' => $roles,
+    );
+  }
 
   if ($notid) {
     $form['create']['mail']['subject'] = array(
@@ -370,32 +409,17 @@
       '#title' => t('Body'),
       '#required' => TRUE,
       '#default_value' => $notification->body,
-      '#description' => t('Enter the body of your notification email.  The following variables can be used in your message and will be automatically replaced before the email is sent:') .'<ul>'
-          .'<li>'. t('%sitename: the name of this website.') 
-          .'<li>'. t('%owner_name: the username of the ad owner.') 
-          .'<li>'. t('%owner_mail: the email address of the ad owner.') 
-          .'<li>'. t('%owner_uid: the user ID of the ad owner.') 
-          .'<li>'. t('%event: the type of event that has triggered this notification.')
-          .'<li>'. t('%count: the number of times the event happened.') 
-          .'<li>'. t('%frequency: a complete sentence describing the frequency this notification will be sent.') 
-          .'<li>'. t('%type: the type of ad.') 
-          .'<li>'. t('%status: the status of the ad.') 
-          .'<li>'. t('%url: the url of the advertisement.') 
-          .'<li>'. t('%siteurl: the url of the website.') 
-          .'<li>'. t('%redirect: the redirection url of the advertisement.') 
-          .'<li>'. t('%title: the title of the advertisement.') 
-          .'<li>'. t('%aid: the ID of the advertisement.') 
-          .'<li>'. t('%comments: the number of comments attached to the advertisement.') 
-          .'<li>'. t('%created_small, %created_medium, %created_large: various formats of when the advertisement was created.') 
-          .'<li>'. t('%activated_small, %activated_medium, %activated_large: various formats of when the advertisement was activated.') 
-          .'<li>'. t('%expired_small, %expired_medium, %expired_large: various formats of when the advertisement was expired.') 
-          .'<li>'. t('%autoactivate_small, %autoactivate_medium, %autoactivate_large: various formats of when the advertisement was automatically activated.') 
-          .'<li>'. t('%autoexpire_small, %autoexpire_medium, %autoexpire_large: various formats of when the advertisement was automatically expired.') 
-          .'<li>'. t('%maxviews: the maximum number of times this advertisement is allowed to be viewed.') 
-          .'<li>'. t('%maxclicks: the maximum number of times this advertisement is allowed to be clicked.') 
-          .'<li>'. t('%global_views, %global_clicks, %last_year_views, %last_year_clicks, %this_year_views, %this_year_clicks, %last_month_views, %last_month_clicks, %this_month_views, %this_month_clicks, %this_week_views, %this_week_clicks, %yesterday_views, %yesterday_clicks, %today_views, %today_clicks, %last_hour_views, %last_hour_clicks, %this_hour_views, %this_hour_clicks: various advertisement statistics')
-          .'</ul>',
     );
+    $form['create']['mail']['tokens'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Replacement patterns'),
+      '#collapsible' => TRUE,
+      '#collapsed' => TRUE,
+    );
+    $form['create']['mail']['tokens']['list'] = array(
+      '#value' => theme('token_help', 'ad', '%', ''),
+    );
+    $form['create']['roles']['#default_value'] = $notification->roles;
   }
 
   $form['create']['oid'] = array(
@@ -405,12 +429,12 @@
 
   $form['create']['aid'] = array(
     '#type' => 'hidden',
-    '#value' => $node->nid,
+    '#value' => $nid,
   );
 
   $form['create']['uid'] = array(
     '#type' => 'hidden',
-    '#value' => $owner->uid,
+    '#value' => $uid,
   );
 
   if ($notid) {
@@ -446,10 +470,17 @@
   else {
     $form['notifications'] = array(
       '#type' => 'markup',
-      '#value' => '<p>'. t('There are no notifications configured for %owner.', array('%owner' => $owner->name)) .'</p>',
+      '#value' => '<p>'. t('There are no notifications configured yet.') .'</p>',
     );
   }
 
+  if ($user->name == $owner->name) {
+    drupal_set_title('My notifications');
+  }
+  else {
+    drupal_set_title('Notifications');
+  }
+
   return $form;
 }
 
@@ -457,29 +488,16 @@
  * Validate ad notifications before saving to database.
  */
 function ad_notify_overview_form_validate($form, &$form_state) {
-  $redirect = FALSE;
   if ($form_state['values']['event'] == 'regular' && $form_state['values']['delay'] < 3600) {
-    drupal_set_message(t('You are not allowed to schedule a regular notification more frequently than once an hour.'), 'error');
-    $redirect = TRUE;
+    form_set_error('form', t('You are not allowed to schedule a regular notification more frequently than once an hour.'));
   }
   else if (!isset($form_state['values']['notid'])) {
     if (db_result(db_query("SELECT notid FROM {ad_notify} WHERE oid = %d AND event = '%s' AND delay = %d", $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay']))) {
-      drupal_set_message(t('You have already scheduled that notification.'), 'error');
-      $redirect = TRUE;
+      form_set_error('form', t('You have already scheduled that notification.'));
     }
   }
   else if ($form_state['values']['locked'] && !ad_permission($form_state['values']['aid'], 'manage owners')) {
-    $redirect = TRUE;
-    drupal_set_message(t('This notification is locked, you will need to contact the site administrator to edit this notification for you.'), 'error');
-  }
-
-  if ($redirect) {
-    if (arg(2) == 'adowners' && arg(4) == 'notifications') {
-      drupal_goto('node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications');
-    }
-    else {
-      drupal_goto('node/'. $form_state['values']['aid'] .'/notifications');
-    }
+    form_set_error('form', t('This notification is locked, you will need to contact the site administrator to edit this notification for you.'));
   }
 }
 
@@ -488,7 +506,7 @@
  */
 function ad_notify_overview_form_submit($form, &$form_state) {
   if (isset($form_state['values']['notid'])) {
-    db_query("UPDATE {ad_notify} SET aid = %d, oid = %d, event = '%s', delay = %d, expire = %d, locked = %d, status = %d, address = '%s', subject = '%s', body = '%s' WHERE notid = %d", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $form_state['values']['address'], $form_state['values']['subject'], $form_state['values']['body'], $form_state['values']['notid']);
+    db_query("UPDATE {ad_notify} SET aid = %d, oid = %d, event = '%s', delay = %d, expire = %d, locked = %d, status = %d, address = '%s', subject = '%s', body = '%s', roles = '%s' WHERE notid = %d", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $form_state['values']['address'], $form_state['values']['subject'], $form_state['values']['body'], serialize($form_state['values']['roles']), $form_state['values']['notid']);
     drupal_set_message('Notification updated.');
   }
   else {
@@ -501,30 +519,34 @@
         'body' => t("Hello %owner_name,\n\n  This is an automatically generated notification about your advertisement \"%title\" that is being displayed on the %sitename website.\n\n  Your advertisement has been viewed %today_views times and clicked %today_clicks times today.  It was viewed %yesterday_views times and clicked %yesterday_clicks times yesterday.  It has been viewed %global_views times and clicked %global_clicks times since it was activated on %activated_large.\n\n  You will receive this %frequency  You can view additional statistics about this advertisement or update this notification at the following url:\n    %url\n\nRegards,\n The %sitename Team\n\n-\n%siteurl"),
       );
     }
-    db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s')", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $form_state['values']['address'], $mail['subject'], $mail['body']);
+    db_query("INSERT INTO {ad_notify} (aid, oid, event, delay, expire, locked, status, address, subject, body, roles) VALUES(%d, %d, '%s', %d, %d, %d, %d, '%s', '%s', '%s', '%s')", $form_state['values']['aid'], $form_state['values']['oid'], $form_state['values']['event'], $form_state['values']['delay'], $form_state['values']['expire'], $form_state['values']['locked'], AD_NOTIFY_ENABLED, $form_state['values']['address'], $mail['subject'], $mail['body'], serialize($form_state['values']['roles']));
     drupal_set_message('Notification created.');
   }
-  $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
+
+  if ($form_state['values']['aid'] && $form_state['values']['uid']) {
+    $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
+  }
+  else if ($form_state['values']['aid']) {
+    $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/notifications';
+  }
+  else {
+    $form_state['redirect'] = 'admin/content/ad/notifications';
+  }
 }
 
 /**
  * Load a specified notification from the database, return as an object.
  */
 function ad_notification_load($notid) {
-  return db_fetch_object(db_query('SELECT * FROM {ad_notify} WHERE notid = %d', $notid));
-}
-
-/**
- * Display confirm form.
- */
-function ad_notify_confirm_delete_page($node, $owner, $notification) {
-  return drupal_get_form('ad_notify_confirm_delete', $node, $owner, $notification);
+  $notification = db_fetch_object(db_query('SELECT * FROM {ad_notify} WHERE notid = %d', $notid));
+  $notification->roles = unserialize($notification->roles);
+  return $notification;
 }
 
 /**
  * Confirm deletion of a specified notification from the database.
  */
-function ad_notify_confirm_delete(&$form_state, $node, $owner, $notification) {
+function ad_notify_confirm_delete(&$form_state, $nid, $uid, $notification) {
   $form = array();
 
   $form['oid'] = array(
@@ -534,12 +556,12 @@
 
   $form['aid'] = array(
     '#type' => 'hidden',
-    '#value' => $node->nid,
+    '#value' => $nid,
   );
 
   $form['uid'] = array(
     '#type' => 'hidden',
-    '#value' => $owner->uid,
+    '#value' => $uid,
   );
 
   $form['notid'] = array(
@@ -563,11 +585,21 @@
     '#prefix' => '<div class="container-inline">',
     '#suffix' => '</div>',
   );
+  
+  if ($nid && $uid) {
+   $path = 'node/'. $nid .'/adowners/'. $uid .'/notifications';
+  }
+  else if ($nid) {
+    $path = 'node/'. $nid .'/notifications';
+  }
+  else {
+    $path = 'admin/content/ad/notifications';
+  }
 
   $form = confirm_form(
     $form,
     'Are you sure you want to delete this notification?',
-    'node/'. $node->nid .'/adowners/'. $owner->uid .'/notifications',
+    $path,
     'This action cannot be undone.',
     'Delete',
     'Cancel'
@@ -581,13 +613,7 @@
  */
 function ad_notify_confirm_delete_validate($form, &$form_state) {
   if ($form_state['values']['locked'] && !ad_permission($form_state['values']['aid'], 'manage owners')) {
-    drupal_set_message(t('This notification is locked, you will need to contact the site administrator to delete this notification for you.'), 'error');
-    if (arg(2) == 'adowners' && arg(4) == 'notifications') {
-      drupal_goto('node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications');
-    }
-    else {
-      drupal_goto('node/'. $form_state['values']['aid'] .'/notifications');
-    }
+    form_set_error('form', t('This notification is locked, you will need to contact the site administrator to delete this notification for you.'));
   }
 }
 
@@ -597,21 +623,14 @@
 function ad_notify_confirm_delete_submit($form, &$form_state) {
   db_query('DELETE FROM {ad_notify} WHERE notid = %d', $form_state['values']['notid']);
   drupal_set_message('Notification deleted.');
-  $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
-}
-
-/**
- * Implementation of hook_adowners().
- */
-function ad_notify_adowners($op, $arg1 = NULL, $arg2 = NULL) {
-  switch ($op) {
-    case 'overview':
-      return l(t('notifications'), 'node/'. $arg1 .'/adowners/'. $arg2 .'/notifications');
 
-    case 'delete':
-      if ($arg1) {
-        db_query('DELETE FROM {ad_notify} WHERE oid = %d', $arg1);
-      }
-      break;
+  if ($form_state['values']['aid'] && $form_state['values']['uid']) {
+   $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/adowners/'. $form_state['values']['uid'] .'/notifications';
   }
-}
+  else if ($form_state['values']['aid']) {
+    $form_state['redirect'] = 'node/'. $form_state['values']['aid'] .'/notifications';
+  }
+  else {
+    $form_state['redirect'] = 'admin/content/ad/notifications';
+  }
+}
\ No newline at end of file
--- token_ad.inc
+++ token_ad.inc
@@ -0,0 +1,151 @@
+<?php
+// $Id: token_user.inc,v 1.3.4.2 2008/06/28 15:10:22 greggles Exp $
+
+/**
+ * @file
+ * Implementations of token module hooks for the Advertisement module.
+ *
+ * @ingroup token
+ */
+
+/**
+ * Implementation of hook_token_values().
+ */
+function ad_token_values($type, $object = NULL, $options = array()) {
+  $values = array();
+  switch ($type) {
+    case 'ad':
+      if (isset($object)) {
+        $node = $object;
+        $notifications = module_invoke_all('adnotifyapi', 'register');
+        module_load_include('pages.inc', 'ad');
+
+        $values['aid']           = $node->nid;
+        $values['title']         = $node->title;
+        $values['description']   = $node->body;
+        $values['log_message']   = $node->log;
+        $values['type']          = $node->adtype;
+        $values['status']        = $node->adstatus;
+        $values['url']           = url('node/'. $node->nid, array('absolute' => TRUE));
+        $values['redirect']      = url($node->redirect, array('absolute' => TRUE));
+        $values['comments']      = $node->comment_count;
+
+        if (isset($node->notification)) {
+          $values['event']       = $node->notification->event;
+          $values['frequency']   = t(strtolower($notifications[$node->notification->event]), array('@when' => format_interval($node->notification->delay)));
+        }
+
+        $values['created_small'] = format_date($node->created, 'small');
+        $values['created_medium'] = format_date($node->created, 'medium');
+        $values['created_large'] = format_date($node->created, 'large');
+        $values['activated_small'] = $node->activated ? format_date($node->activated, 'small') : t('never');
+        $values['activated_medium'] = $node->activated ? format_date($node->activated, 'medium') : t('never');
+        $values['activated_large'] = $node->activated ? format_date($node->activated, 'large') : t('never');
+        $values['expired_small'] = $node->expired ? format_date($node->expired, 'small') : t('never');
+        $values['expired_medium'] = $node->expired ? format_date($node->expired, 'medium') : t('never');
+        $values['expired_large'] = $node->expired ? format_date($node->expired, 'large') : t('never');
+        $values['autoactivate_small'] = $node->autoactivate ? format_date($node->autoactivate, 'small') : t('never');
+        $values['autoactivate_medium'] = $node->autoactivate ? format_date($node->autoactivate, 'medium') : t('never');
+        $values['autoactivate_large'] = $node->autoactivate ? format_date($node->autoactivate, 'large') : t('never');
+        $values['autoexpire_small'] = $node->autoexpire ? format_date($node->autoexpire, 'small') : t('never');
+        $values['autoexpire_medium'] = $node->autoexpire ? format_date($node->autoexpire, 'medium') : t('never');
+        $values['autoexpire_large'] = $node->autoexpire ? format_date($node->autoexpire, 'large') : t('never');
+
+        $statistics = ad_statistics($node->nid);
+        $values['maxviews'] = $node->maxviews;
+        $values['maxclicks'] = $node->maxclicks;
+        $values['global_views'] = $statistics['global']['views'];
+        $values['global_clicks'] = $statistics['global']['clicks'];
+        $values['last_year_views'] = $statistics['last_year']['views'];
+        $values['last_year_clicks'] = $statistics['last_year']['clicks'];
+        $values['this_year_views'] = $statistics['this_year']['views'];
+        $values['this_year_clicks'] = $statistics['this_year']['clicks'];
+        $values['last_month_views'] = $statistics['last_month']['views'];
+        $values['last_month_clicks'] = $statistics['last_month']['clicks'];
+        $values['this_month_views'] = $statistics['this_month']['views'];
+        $values['this_month_clicks'] = $statistics['this_month']['clicks'];
+        $values['this_week_views'] = $statistics['this_week']['views'];
+        $values['this_week_clicks'] = $statistics['this_week']['clicks'];
+        $values['yesterday_views'] = $statistics['yesterday']['views'];
+        $values['yesterday_clicks'] = $statistics['yesterday']['clicks'];
+        $values['today_views'] = $statistics['today']['views'];
+        $values['today_clicks'] = $statistics['today']['clicks'];
+        $values['last_hour_views'] = $statistics['last_hour']['views'];
+        $values['last_hour_clicks'] = $statistics['last_hour']['clicks'];
+        $values['this_hour_views'] = $statistics['this_hour']['views'];
+        $values['this_hour_clicks'] = $statistics['this_hour']['clicks'];
+      }
+      break;
+    case 'ad_owner':
+      if (isset($object)) {
+        $owner = $object;
+        $values['owner_name']    = $owner->name;
+        $values['owner_mail']    = $owner->mail;
+        $values['owner_uid']     = $owner->uid;
+      }
+      break;
+  }
+  return $values;
+}
+
+/**
+ * Implementation of hook_token_list().
+ */
+function ad_token_list($type = 'all') {
+  if ($type == 'ad' || $type == 'all') {
+    $tokens['ad']['aid']           = t('The ID of the advertisement.');
+    $tokens['ad']['type']          = t('The type of ad.');
+    $tokens['ad']['status']        = t('The status of the ad.');
+    $tokens['ad']['url']           = t('The url of the advertisement.');
+    $tokens['ad']['redirect']      = t('The redirection url of the advertisement.');
+    $tokens['ad']['event']         = t('The type of event that has triggered this notification.');
+    $tokens['ad']['frequency']     = t('A complete sentence describing the frequency this notification will be sent.');
+    $tokens['ad']['title']         = t('The title of the advertisement.');
+    $tokens['ad']['comments']      = t('The number of comments attached to the advertisement.');
+
+    $tokens['ad']['created_small']        = t('"Small" date format of when the advertisement was created.');
+    $tokens['ad']['created_medium']       = t('"Medium" date format of when the advertisement was created.');
+    $tokens['ad']['created_large']        = t('"Large" date format of when the advertisement was created.');
+    $tokens['ad']['activated_small']      = t('"Small" date format when the advertisement was activated.');
+    $tokens['ad']['activated_medium']     = t('"Medium" date format of when the advertisement was activated.');
+    $tokens['ad']['activated_large']      = t('"Large" date format of when the advertisement was activated.');
+    $tokens['ad']['expired_small']        = t('"Small" date format of when the advertisement was expired.');
+    $tokens['ad']['expired_medium']       = t('"Medium" date format of when the advertisement was expired.');
+    $tokens['ad']['expired_large']        = t('"Large" date format of when the advertisement was expired.');
+    $tokens['ad']['autoactivate_small']   = t('"Small" date format of when the advertisement was automatically activated.');
+    $tokens['ad']['autoactivate_medium']  = t('"Medium" date format of when the advertisement was automatically activated.');
+    $tokens['ad']['autoactivate_large']   = t('"Large" date format of when the advertisement was automatically activated.');
+    $tokens['ad']['autoexpire_small']     = t('"Small" date format of when the advertisement was automatically expired.');
+    $tokens['ad']['autoexpire_medium']    = t('"Medium" date format of when the advertisement was automatically expired.');
+    $tokens['ad']['autoexpire_large']     = t('"Large" date format of when the advertisement was automatically expired.');
+
+    $tokens['ad']['maxviews']          = t('The maximum number of times this advertisement is allowed to be viewed.');
+    $tokens['ad']['maxclicks']         = t('The maximum number of times this advertisement is allowed to be clicked.');
+    $tokens['ad']['global_views']      = t('Various advertisement statistics');
+    $tokens['ad']['global_clicks']     = t('Various advertisement statistics');
+    $tokens['ad']['last_year_views']   = t('Various advertisement statistics');
+    $tokens['ad']['last_year_clicks']  = t('Various advertisement statistics');
+    $tokens['ad']['this_year_views']   = t('Various advertisement statistics');
+    $tokens['ad']['this_year_clicks']  = t('Various advertisement statistics');
+    $tokens['ad']['last_month_views']  = t('Various advertisement statistics');
+    $tokens['ad']['last_month_clicks'] = t('Various advertisement statistics');
+    $tokens['ad']['this_month_views']  = t('Various advertisement statistics');
+    $tokens['ad']['this_month_clicks'] = t('Various advertisement statistics');
+    $tokens['ad']['this_week_views']   = t('Various advertisement statistics');
+    $tokens['ad']['this_week_clicks']  = t('Various advertisement statistics');
+    $tokens['ad']['yesterday_views']   = t('Various advertisement statistics');
+    $tokens['ad']['yesterday_clicks']  = t('Various advertisement statistics');
+    $tokens['ad']['today_views']       = t('Various advertisement statistics');
+    $tokens['ad']['today_clicks']      = t('Various advertisement statistics');
+    $tokens['ad']['last_hour_views']   = t('Various advertisement statistics');
+    $tokens['ad']['last_hour_clicks']  = t('Various advertisement statistics');
+    $tokens['ad']['this_hour_views']   = t('Various advertisement statistics');
+    $tokens['ad']['this_hour_clicks']  = t('Various advertisement statistics');
+  }
+  if ($type == 'ad' || $type == 'all') {
+    $tokens['Ad owner']['owner_name']  = t('The username of the ad owner.');
+    $tokens['Ad owner']['owner_mail']  = t('The email address of the ad owner.');
+    $tokens['Ad owner']['owner_uid']   = t('The user ID of the ad owner.');
+  }
+  return $tokens;
+}


