Index: sites/all/modules/contrib/chartbeat/chartbeat.module
===================================================================
--- sites/all/modules/contrib/chartbeat/chartbeat.module	(revision 514)
+++ sites/all/modules/contrib/chartbeat/chartbeat.module	(working copy)
@@ -29,8 +29,9 @@ function chartbeat_perm() {
  * Implementation of hook_init().
  */
 function chartbeat_init() {
+  global $user;
   $uid = variable_get('chartbeat_uid', '');
-  if (is_numeric($uid)) {
+  if (is_numeric($uid) && _chartbeat_visibility_pages() && _chartbeat_visibility_roles($user) && _chartbeat_visibility_custom()) {
     drupal_set_html_head('<script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script>');
     drupal_add_js(array('chartbeat' => array(
       'uid' => (int)$uid,
@@ -43,8 +44,10 @@ function chartbeat_init() {
  * Implementation of hook_footer().
  */
 function chartbeat_footer() {
+  global $user;
   $uid = variable_get('chartbeat_uid', '');
-  if (is_numeric($uid)) {
+  $uid = variable_get('chartbeat_uid', '');
+  if (is_numeric($uid) && _chartbeat_visibility_pages() && _chartbeat_visibility_roles($user) && _chartbeat_visibility_custom()) {
     $output = <<<EOT
 <script type="text/javascript">
   var _sf_async_config=Drupal.settings.chartbeat;
@@ -68,3 +71,86 @@ EOT;
     return $output;
   }
 }
+
+/**
+ * Based on visibility setting this function returns TRUE if Chartbeat code
+ * should be added for the current role and otherwise FALSE.
+ */
+function _chartbeat_visibility_roles($account) {
+
+  $enabled = FALSE;
+  $roles = variable_get('chartbeat_roles', array());
+
+  if (array_sum($roles) > 0) {
+    // One or more roles are selected for tracking.
+    foreach (array_keys($account->roles) as $rid) {
+      // Is the current user a member of one role enabled for tracking?
+      if (isset($roles[$rid]) && $rid == $roles[$rid]) {
+        // Current user is a member of a role that should be tracked.
+        $enabled = TRUE;
+        break;
+      }
+    }
+  }
+  else {
+    // No role is selected for tracking, therefor all roles should be tracked.
+    $enabled = TRUE;
+  }
+
+  return $enabled;
+}
+
+/**
+ * Based on visibility setting this function returns TRUE if Chartbeat code
+ * should be added to the current page and otherwise FALSE.
+ */
+function _chartbeat_visibility_pages() {
+  static $page_match;
+
+  // Cache visibility setting in hook_init for hook_footer.
+  if (!isset($page_match)) {
+
+    $visibility = variable_get('chartbeat_visibility', 0);
+    $pages = variable_get('chartbeat_pages', '');
+
+    // Match path if necessary.
+    if (!empty($pages)) {
+      if ($visibility < 2) {
+        $path = drupal_get_path_alias($_GET['q']);
+        // Compare with the internal and path alias (if any).
+        $page_match = drupal_match_path($path, $pages);
+        if ($path != $_GET['q']) {
+          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
+        }
+        // When $visibility has a value of 0, the block is displayed on
+        // all pages except those listed in $pages. When set to 1, it
+        // is displayed only on those pages listed in $pages.
+        $page_match = !($visibility xor $page_match);
+      }
+      else {
+        $page_match = drupal_eval($pages);
+      }
+    }
+    else {
+      $page_match = TRUE;
+    }
+
+  }
+  return $page_match;
+}
+
+/**
+ * Returns TRUE only if no other module objects to including Chartbeat
+ *
+ * @see hook_chartbeat_visibility()
+ */
+function _chartbeat_visibility_custom() {
+  static $custom_match;
+
+  if (!isset($custom_match)) {
+    $res = module_invoke_all('chartbeat_visibility');
+    $custom_match = (array_search(FALSE, $res, true) === FALSE);
+  }
+
+  return $custom_match;
+}
Index: sites/all/modules/contrib/chartbeat/chartbeat.api.php
===================================================================
--- sites/all/modules/contrib/chartbeat/chartbeat.api.php	(revision 0)
+++ sites/all/modules/contrib/chartbeat/chartbeat.api.php	(revision 0)
@@ -0,0 +1,20 @@
+<?php
+
+/**
+ * Hook to block the inclusion of Chartbeat tracking code on a page by page
+ * basis. Note that this hook is only checked after the role and page filters
+ * would normally allow Chartbeat to be included on the page.
+ *
+ * Only one module needs to return FALSE to block Chartbeat from loading
+ *
+ * @return bool
+ *   Return FALSE to block inclusion of Chartbeat. Any other return value
+ *   will allow it.
+ */
+function hook_chartbeat_visibility() {
+  // Example: Only include Chartbeat tracking code during peak time - 8am to 10am
+  $hour = date('H');
+  if ($hour <= 8 || $hour >= 10) {
+    return FALSE;
+  }
+}
Index: sites/all/modules/contrib/chartbeat/chartbeat.admin.inc
===================================================================
--- sites/all/modules/contrib/chartbeat/chartbeat.admin.inc	(revision 514)
+++ sites/all/modules/contrib/chartbeat/chartbeat.admin.inc	(working copy)
@@ -5,17 +5,87 @@
  * Menu callback for the String Overrides module to display its administration
  */
 function chartbeat_admin_settings() {
-  $form['chartbeat_uid'] = array(
+  $form['account'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('General settings'),
+    '#collapsible' => FALSE,
+  );
+  $form['account']['chartbeat_uid'] = array(
     '#type' => 'textfield',
     '#title' => t('User ID'),
     '#description' => t('The user ID associated with your <a href="@chartbeat">Chartbeat</a> account.', array('@chartbeat' => 'http://chartbeat.com')),
     '#default_value' => variable_get('chartbeat_uid', ''),
   );
-  $form['chartbeat_domain'] = array(
+  $form['account']['chartbeat_domain'] = array(
     '#type' => 'textfield',
     '#title' => t('Domain'),
     '#description' => t('The domain to be reporting from on your account.'),
     '#default_value' => variable_get('chartbeat_domain', ''),
   );
+  $form['role_vis_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Role specific tracking settings'),
+    '#collapsible' => TRUE,
+  );
+
+  $roles = user_roles();
+  $role_options = array();
+  foreach ($roles as $rid => $name) {
+    $role_options[$rid] = $name;
+  }
+  $form['role_vis_settings']['chartbeat_roles'] = array(
+    '#type' => 'checkboxes',
+    '#title' => t('Add tracking for specific roles'),
+    '#default_value' => variable_get('chartbeat_roles', array()),
+    '#options' => $role_options,
+    '#description' => t('Add tracking only for the selected role(s). If none of the roles are selected, all users will be tracked. If a user has any of the roles checked, that user will be tracked.'),
+  );
+
+  $form['page_vis_settings'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Page specific tracking settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+  );
+
+  $access = user_access('use PHP for tracking visibility');
+  $visibility = variable_get('chartbeat_visibility', 0);
+  $pages = variable_get('chartbeat_pages', '');
+
+  if ($visibility == 2 && !$access) {
+    $form['page_vis_settings'] = array();
+    $form['page_vis_settings']['visibility'] = array('#type' => 'value', '#value' => 2);
+    $form['page_vis_settings']['pages'] = array('#type' => 'value', '#value' => $pages);
+  }
+  else {
+    $options = array(t('Add to every page except the listed pages.'), t('Add to the listed pages only.'));
+    $description = t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>'));
+
+    if ($access) {
+      $options[] = t('Add if the following PHP code returns <code>TRUE</code> (PHP-mode, experts only).');
+      $description .= ' '. t('If the PHP-mode is chosen, enter PHP code between %php. Note that executing incorrect PHP-code can break your Drupal site.', array('%php' => '<?php ?>'));
+    }
+    $form['page_vis_settings']['chartbeat_visibility'] = array(
+      '#type' => 'radios',
+      '#title' => t('Add tracking to specific pages'),
+      '#options' => $options,
+      '#default_value' => $visibility,
+    );
+    $form['page_vis_settings']['chartbeat_pages'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Pages'),
+      '#default_value' => $pages,
+      '#description' => $description,
+      '#wysiwyg' => FALSE,
+    );
+  }
   return system_settings_form($form);
 }
+
+/**
+ * Validate callback for settings form
+ */
+function chartbeat_admin_settings_validate($form, &$form_state) {
+  // Trim some text area values.
+  $form_state['values']['chartbeat_pages'] = trim($form_state['values']['chartbeat_pages']);
+}
